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

vultisig / vultisig-ios

Vultisig iOS App

SwiftApache-2.0★ 40 星标⑂ 22 复刻始于 2024年1月在 GitHub 上查看 ↗

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

68
总分 / 100
中等

软件健康指数

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

68
优秀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,740 次提交
10/10OpenSSF Scorecard:Maintained — 30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
所用输入
commits_last_year1,740
human_commit_share1
days_since_last_push0
active_weeks_last_year52

发布纪律

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

社区与采用

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

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

流行度与采用

40存在风险
评分方式
25.8/60星标 — 40 个星标
11/25复刻 — 22 个复刻
2.7/15关注者 — 4 位关注者
所用输入
forks22
stars40
watchers4
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

可持续性与治理

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

73良好 · 占总体的 24%
评分方式
25.2/54巴士系数 — 2 位贡献者贡献了半数提交
15.2/22.5提交分布 — 头号贡献者编写了 32% 的提交
13.5/13.5贡献者广度 — 27 位贡献者
10/10OpenSSF Scorecard:Contributors — project has 4 contributing companies or organizations
所用输入
bus_factor2
contributors_sampled27
top_contributor_share0.325
评分方式
46.3/46.8议题解决 — 99% 的议题已关闭
36.3/38.3PR 接受 — 已裁定的 PR 中 2,508/2,641 已合并
12/15OpenSSF Scorecard:Code-Review — Found 26/30 approved changesets -- score normalized to 8
所用输入
merged_prs2,508
open_issues20
closed_issues2,185
issue_closed_ratio0.991
closed_unmerged_prs133
评分方式
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

工程质量

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

61中等 · 占总体的 20%

工程实践

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

文档

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

安全

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

54中等 · 占总体的 16%

安全态势

43存在风险
评分方式
0/7.5Binary-Artifacts — binaries present in source code
3.8/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 29 out of 29 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/7.5Code-Review — Found 26/30 approved changesets -- score normalized to 8
2.5/2.5Contributors — project has 4 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
7.5/7.5Maintained — 30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — 无数据
5/5Pinned-Dependencies — all dependencies are pinned
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
3/7.5Vulnerabilities — 6 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate4.3
已排除计分(无数据或不适用):packaging。 其余权重已重新归一化。
评分方式
35/35直接依赖不含已知公告 — 没有直接依赖携带已知公告
0/25间接依赖不含已知公告 — 在此范围内,传递依赖集合无法与开发和测试依赖区分
0/40没有长期未处理的公告 — 没有公告带有发布日期
所用输入
sourceosv
advisories6
affected_packages5
assessed_packages105
unassessed_packages0
affected_by_severityhigh 4, moderate 1
direct_affected_packages0
已排除计分(无数据或不适用):间接依赖不含已知公告, 没有长期未处理的公告。 其余权重已重新归一化。 已将 105 个已解析依赖与 OSV 比对。 该仓库未发布任何索引可解析的软件包,因此改为评估仓库依赖图。该图将开发与测试版本固定同交付的依赖混在一起,因此仅对声明的运行时依赖计分;传递性发现仅作为背景信息列出,不计入评分。 未对可达性进行分析。

AI 就绪度

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

86优秀 · 占总体的 0%
评分方式
45/45代理指令 — AGENTS.md, CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 99 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.99
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes7,403
评分方式
18/18一条命令的引导启动 — Makefile
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — Swift(静态类型)
10/10可复现环境 — lockfile
10/10已体现的代理实践 — 最近 100 次提交中有 77 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
10/10OpenSSF Scorecard:Pinned-Dependencies — all dependencies are pinned
所用输入
has_nix
has_tests
lockfilesGemfile.lock, package-lock.json
has_dockerfile
typed_language
bootstrap_filesMakefile
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0.77
toolchain_manifests
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — Swift(静态类型)
54.9/55可控的文件大小 — 采样的 1,876 个源文件中有 3 个超过 60KB
所用输入
primary_languageSwift
largest_source_bytes78,072
source_files_sampled1,876
oversized_source_files3

关键数据

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

更多细节

Star 与 Fork 历史 40 ★ / 22 ⇿
40Star
22Fork
100发布

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

010203040402222024-032025-052026-07
主版本 0次版本 13修订 87

每个点涵盖 3 天。

OpenSSF Scorecard 4.3 / 10
4.3综合

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

0Binary-Artifactsbinaries present in source code
5Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests29 out of 29 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
8Code-ReviewFound 26/30 approved changesets -- score normalized to 8
10Contributorsproject has 4 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
不适用Packagingpackaging workflow not detected
10Pinned-Dependenciesall dependencies are pinned
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
4Vulnerabilities6 existing vulnerabilities detected
直接依赖 2
注册表软件包版本约束清单文件
RubyGemsfastlane2.229.1VultisigApp/Gemfile
RubyGemsostructVultisigApp/Gemfile
全部依赖 105

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

注册表软件包版本关系
RubyGemsfastlane2.229.1直接
RubyGemsostruct0.6.3直接
npm@cosmjs/crypto0.39.0间接
npm@cosmjs/encoding0.39.0间接
npm@cosmjs/math0.39.0间接
npm@cosmjs/utils0.39.0间接
npm@noble/ciphers2.2.0间接
npm@noble/curves2.2.0间接
npm@noble/hashes2.2.0间接
npm@scure/base2.2.0间接
npm@scure/bip392.2.0间接
npmbase64-js1.5.1间接
npmcosmjs-types0.11.0间接
npmreadonly-date-esm2.0.0间接
RubyGemsabbrev0.1.2间接
RubyGemsaddressable2.8.8间接
RubyGemsartifactory3.0.17间接
RubyGemsatomos0.1.3间接
RubyGemsaws-eventstream1.4.0间接
RubyGemsaws-partitions1.1211.0间接
RubyGemsaws-sdk-core3.241.4间接
RubyGemsaws-sdk-kms1.121.0间接
RubyGemsaws-sdk-s31.213.0间接
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.8.0间接
RubyGemsfaraday-cookie_jar0.0.8间接
RubyGemsfaraday-em_http1.0.0间接
RubyGemsfaraday-em_synchrony1.0.1间接
RubyGemsfaraday-excon1.1.0间接
RubyGemsfaraday-httpclient1.0.1间接
RubyGemsfaraday-net_http1.0.2间接
RubyGemsfaraday-net_http_persistent1.2.0间接
RubyGemsfaraday-patron1.0.0间接
RubyGemsfaraday-rack1.0.0间接
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.18.0间接
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.2间接
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间接
依赖安全公告 5

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

软件包版本关系严重程度公告数修复版本
addressable2.8.8间接12.9.0
faraday1.8.0间接22.14.3
json2.18.0间接12.19.2
jwt2.10.2间接13.2.0
excon0.112.0间接11.5.0

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 744010,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "C": 194496,
        "Ruby": 2537,
        "Shell": 5766,
        "Swift": 9535004,
        "Python": 9583,
        "Makefile": 4040,
        "JavaScript": 7811,
        "Objective-C": 37152
      },
      "pushed_at": "2026-07-21T22:56:12Z",
      "created_at": "2024-01-28T02:41:10Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-21T22:56:15Z",
      "description": "Vultisig iOS App",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Swift",
      "significant_languages": [
        "Swift"
      ]
    },
    "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.42.67",
          "kind": "patch",
          "published_at": "2026-07-17T01:06:25Z"
        },
        {
          "tag": "v1.42.66",
          "kind": "patch",
          "published_at": "2026-07-14T05:07:23Z"
        },
        {
          "tag": "v1.41.65",
          "kind": "patch",
          "published_at": "2026-07-04T01:47:01Z"
        },
        {
          "tag": "v1.41.64",
          "kind": "patch",
          "published_at": "2026-07-03T00:09:35Z"
        },
        {
          "tag": "v1.40.63",
          "kind": "patch",
          "published_at": "2026-06-23T23:52:02Z"
        },
        {
          "tag": "v1.40.62",
          "kind": "patch",
          "published_at": "2026-06-21T23:32:15Z"
        },
        {
          "tag": "v1.39.61",
          "kind": "patch",
          "published_at": "2026-06-12T06:45:39Z"
        },
        {
          "tag": "v1.39.60",
          "kind": "patch",
          "published_at": "2026-06-09T23:44:54Z"
        },
        {
          "tag": "v1.38.59",
          "kind": "patch",
          "published_at": "2026-06-05T22:23:33Z"
        },
        {
          "tag": "v1.38.58",
          "kind": "patch",
          "published_at": "2026-06-05T10:09:35Z"
        },
        {
          "tag": "v1.37.57",
          "kind": "patch",
          "published_at": "2026-05-25T03:12:30Z"
        },
        {
          "tag": "v1.37.56",
          "kind": "patch",
          "published_at": "2026-05-24T03:11:09Z"
        },
        {
          "tag": "v1.36.55",
          "kind": "patch",
          "published_at": "2026-05-05T23:12:19Z"
        },
        {
          "tag": "v1.36.54",
          "kind": "patch",
          "published_at": "2026-05-04T21:58:51Z"
        },
        {
          "tag": "v1.36.53",
          "kind": "patch",
          "published_at": "2026-05-02T01:05:44Z"
        },
        {
          "tag": "v1.36.52",
          "kind": "patch",
          "published_at": "2026-04-30T00:10:17Z"
        },
        {
          "tag": "v1.36.51",
          "kind": "patch",
          "published_at": "2026-04-29T01:15:23Z"
        },
        {
          "tag": "v1.35.50",
          "kind": "patch",
          "published_at": "2026-03-27T04:21:24Z"
        },
        {
          "tag": "v1.35.49",
          "kind": "patch",
          "published_at": "2026-03-22T22:41:43Z"
        },
        {
          "tag": "v1.34.48",
          "kind": "patch",
          "published_at": "2026-03-09T22:47:02Z"
        },
        {
          "tag": "v1.34.47",
          "kind": "patch",
          "published_at": "2026-03-03T22:32:15Z"
        },
        {
          "tag": "v1.34.46",
          "kind": "patch",
          "published_at": "2026-03-01T22:42:30Z"
        },
        {
          "tag": "v1.33.45",
          "kind": "patch",
          "published_at": "2026-02-17T19:46:06Z"
        },
        {
          "tag": "v1.33.44",
          "kind": "patch",
          "published_at": "2026-02-12T21:27:53Z"
        },
        {
          "tag": "v1.33.43",
          "kind": "patch",
          "published_at": "2026-02-09T21:44:54Z"
        },
        {
          "tag": "v1.33.42",
          "kind": "patch",
          "published_at": "2026-02-05T23:11:01Z"
        },
        {
          "tag": "v1.33.41",
          "kind": "patch",
          "published_at": "2026-02-03T22:07:43Z"
        },
        {
          "tag": "1.33.40",
          "kind": "patch",
          "published_at": "2026-02-01T19:47:43Z"
        },
        {
          "tag": "1.33.39",
          "kind": "patch",
          "published_at": "2026-01-28T08:59:24Z"
        },
        {
          "tag": "v1.32.38",
          "kind": "patch",
          "published_at": "2026-01-12T21:54:13Z"
        },
        {
          "tag": "v1.32.37",
          "kind": "patch",
          "published_at": "2026-01-09T08:32:44Z"
        },
        {
          "tag": "v1.32.36",
          "kind": "patch",
          "published_at": "2026-01-06T05:50:12Z"
        },
        {
          "tag": "v1.32.35",
          "kind": "patch",
          "published_at": "2025-12-22T08:19:07Z"
        },
        {
          "tag": "v1.31.34",
          "kind": "patch",
          "published_at": "2025-12-08T22:26:54Z"
        },
        {
          "tag": "v1.31.32",
          "kind": "patch",
          "published_at": "2025-12-08T02:59:16Z"
        },
        {
          "tag": "v1.31.31",
          "kind": "patch",
          "published_at": "2025-12-05T02:46:48Z"
        },
        {
          "tag": "v1.31.30",
          "kind": "patch",
          "published_at": "2025-11-29T03:01:37Z"
        },
        {
          "tag": "v1.30.29",
          "kind": "patch",
          "published_at": "2025-11-25T23:14:01Z"
        },
        {
          "tag": "v1.29.28",
          "kind": "patch",
          "published_at": "2025-11-21T09:08:08Z"
        },
        {
          "tag": "v1.29.27",
          "kind": "patch",
          "published_at": "2025-11-19T21:51:00Z"
        },
        {
          "tag": "v1.29.26",
          "kind": "patch",
          "published_at": "2025-11-17T22:48:06Z"
        },
        {
          "tag": "v1.29.25",
          "kind": "patch",
          "published_at": "2025-11-15T00:16:18Z"
        },
        {
          "tag": "v1.29.24",
          "kind": "patch",
          "published_at": "2025-11-12T22:58:47Z"
        },
        {
          "tag": "v1.28.23",
          "kind": "patch",
          "published_at": "2025-11-04T07:01:05Z"
        },
        {
          "tag": "v1.28.22",
          "kind": "patch",
          "published_at": "2025-11-03T07:59:41Z"
        },
        {
          "tag": "v1.28.21",
          "kind": "patch",
          "published_at": "2025-10-30T22:34:43Z"
        },
        {
          "tag": "v1.28.20",
          "kind": "patch",
          "published_at": "2025-10-28T23:30:48Z"
        },
        {
          "tag": "v1.27.19",
          "kind": "patch",
          "published_at": "2025-10-22T21:57:35Z"
        },
        {
          "tag": "v1.27.18",
          "kind": "patch",
          "published_at": "2025-10-20T03:03:07Z"
        },
        {
          "tag": "v1.27.17",
          "kind": "patch",
          "published_at": "2025-10-15T22:27:49Z"
        },
        {
          "tag": "v1.27.16",
          "kind": "patch",
          "published_at": "2025-10-07T22:39:41Z"
        },
        {
          "tag": "v1.26.15",
          "kind": "patch",
          "published_at": "2025-10-07T01:12:40Z"
        },
        {
          "tag": "v1.26.14",
          "kind": "patch",
          "published_at": "2025-10-03T23:23:01Z"
        },
        {
          "tag": "v1.26.13",
          "kind": "patch",
          "published_at": "2025-10-02T23:39:59Z"
        },
        {
          "tag": "v1.26.12",
          "kind": "patch",
          "published_at": "2025-10-02T02:21:06Z"
        },
        {
          "tag": "v1.26.11",
          "kind": "patch",
          "published_at": "2025-09-30T22:55:01Z"
        },
        {
          "tag": "v1.26.10",
          "kind": "patch",
          "published_at": "2025-09-24T04:33:12Z"
        },
        {
          "tag": "v1.26.9",
          "kind": "patch",
          "published_at": "2025-09-19T23:37:15Z"
        },
        {
          "tag": "v1.25.8",
          "kind": "patch",
          "published_at": "2025-09-14T02:00:02Z"
        },
        {
          "tag": "v1.25.7",
          "kind": "patch",
          "published_at": "2025-09-11T11:02:49Z"
        },
        {
          "tag": "v1.25.6",
          "kind": "patch",
          "published_at": "2025-09-10T21:52:33Z"
        },
        {
          "tag": "v1.25.5",
          "kind": "patch",
          "published_at": "2025-09-09T23:13:40Z"
        },
        {
          "tag": "v1.25.0",
          "kind": "minor",
          "published_at": "2025-09-08T04:16:08Z"
        },
        {
          "tag": "v1.24.3",
          "kind": "patch",
          "published_at": "2025-09-02T23:03:21Z"
        },
        {
          "tag": "v1.24.2",
          "kind": "patch",
          "published_at": "2025-09-01T23:32:43Z"
        },
        {
          "tag": "v1.24.0",
          "kind": "minor",
          "published_at": "2025-08-28T09:59:53Z"
        },
        {
          "tag": "v1.23.5",
          "kind": "patch",
          "published_at": "2025-08-18T23:20:19Z"
        },
        {
          "tag": "v1.23.4",
          "kind": "patch",
          "published_at": "2025-08-18T07:18:39Z"
        },
        {
          "tag": "v1.23.3",
          "kind": "patch",
          "published_at": "2025-08-14T23:29:04Z"
        },
        {
          "tag": "v1.23.2",
          "kind": "patch",
          "published_at": "2025-08-13T04:11:03Z"
        },
        {
          "tag": "v1.23.1",
          "kind": "patch",
          "published_at": "2025-08-07T22:16:47Z"
        },
        {
          "tag": "v1.23.0",
          "kind": "minor",
          "published_at": "2025-08-03T23:00:29Z"
        },
        {
          "tag": "v1.22.3",
          "kind": "patch",
          "published_at": "2025-07-28T04:00:29Z"
        },
        {
          "tag": "v1.22.2",
          "kind": "patch",
          "published_at": "2025-07-24T23:47:32Z"
        },
        {
          "tag": "v1.22.1",
          "kind": "patch",
          "published_at": "2025-07-22T23:38:11Z"
        },
        {
          "tag": "v1.22.0",
          "kind": "minor",
          "published_at": "2025-07-17T23:47:20Z"
        },
        {
          "tag": "v1.21.2",
          "kind": "patch",
          "published_at": "2025-06-27T06:27:04Z"
        },
        {
          "tag": "v1.21.1",
          "kind": "patch",
          "published_at": "2025-06-25T21:41:40Z"
        },
        {
          "tag": "v1.21.0",
          "kind": "minor",
          "published_at": "2025-06-20T04:23:29Z"
        },
        {
          "tag": "v1.20.2",
          "kind": "patch",
          "published_at": "2025-06-10T23:40:21Z"
        },
        {
          "tag": "v1.20.1",
          "kind": "patch",
          "published_at": "2025-06-09T00:15:35Z"
        },
        {
          "tag": "v1.20.0",
          "kind": "minor",
          "published_at": "2025-06-04T10:28:18Z"
        },
        {
          "tag": "v1.19.0",
          "kind": "minor",
          "published_at": "2025-05-27T22:51:42Z"
        },
        {
          "tag": "v1.18.2",
          "kind": "patch",
          "published_at": "2025-05-18T21:32:00Z"
        },
        {
          "tag": "v1.18.1",
          "kind": "patch",
          "published_at": "2025-05-16T11:09:18Z"
        },
        {
          "tag": "v1.18.0",
          "kind": "minor",
          "published_at": "2025-05-13T22:27:13Z"
        },
        {
          "tag": "v1.17.4",
          "kind": "patch",
          "published_at": "2025-05-10T01:10:58Z"
        },
        {
          "tag": "v1.17.3",
          "kind": "patch",
          "published_at": "2025-05-09T06:06:04Z"
        },
        {
          "tag": "v1.17.2",
          "kind": "patch",
          "published_at": "2025-05-07T00:45:47Z"
        },
        {
          "tag": "v1.17.1",
          "kind": "patch",
          "published_at": "2025-05-03T07:24:23Z"
        },
        {
          "tag": "v1.17.0",
          "kind": "minor",
          "published_at": "2025-05-02T03:39:45Z"
        },
        {
          "tag": "v1.16.1",
          "kind": "patch",
          "published_at": "2025-05-01T04:47:07Z"
        },
        {
          "tag": "v1.16.0",
          "kind": "minor",
          "published_at": "2025-04-30T00:11:24Z"
        },
        {
          "tag": "v1.15.3",
          "kind": "patch",
          "published_at": "2025-04-15T14:38:10Z"
        },
        {
          "tag": "v1.15.2",
          "kind": "patch",
          "published_at": "2025-04-14T07:20:23Z"
        },
        {
          "tag": "v1.15.1",
          "kind": "patch",
          "published_at": "2025-04-07T03:15:45Z"
        },
        {
          "tag": "v1.15.0",
          "kind": "minor",
          "published_at": "2025-03-26T23:01:19Z"
        },
        {
          "tag": "v1.14.0",
          "kind": "minor",
          "published_at": "2025-03-19T21:54:07Z"
        },
        {
          "tag": "v1.13.4",
          "kind": "patch",
          "published_at": "2025-03-12T21:52:35Z"
        },
        {
          "tag": "v1.13.0",
          "kind": "minor",
          "published_at": "2025-03-08T00:44:04Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "9fc8f630bcfc6e1947d5b2d07ecf778bdd7fb16e",
          "body": "…tput (#4851)\n\n`buildThorchainSwapPayload` derived `toAmountLimit` as\n`expectedAmountOut * (10000 - toleranceBps) / 10000`, but no production\ncaller ever passed `toleranceBps` — it defaulted to\n`SwapService.defaultThorchainToleranceBps` (0) at all four call sites. The\npayload therefore claimed a min\n[…]\ne memo yields \"0\", which honestly means \"no floor asserted\";\nfalling back to the expected output is precisely the bug being fixed.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): derive toAmountLimit from the signed memo, not expected ou…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-21T22:35:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "137126da01e989d6d4edde0a4642b4c197740010",
          "body": "… % from bps, reconciled total (#4864)\n\n* Shared effective-affiliate-bps function; % from bps not fiat division\n\nExtract the effective affiliate-bps computation into THORChainSwaps\n(discountedAffiliateBps + effectiveAffiliateFeeBps) and have the three\nquote-request builders (ThorchainService/Mayacha\n[…]\nch site (ranking/hash/signing/service construction) and tests.\n\nDisplay/enum-shape only; SwapPayloadBuilder and the signed memo/amount are\nuntouched. Ranking reads outAmount (already net), unaffected.",
          "is_bot": false,
          "headline": "fix(swap): itemize the Verify fee rows — affiliate-only Vultisig Fee,…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-21T22:25:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d71d2f2c268dfff890a72abb0c24af9da78aebef",
          "body": "…parate cards (#4865)\n\n* feat(defi): read the RUJI auto-compounding position size from the staking API\n\nRujira's RUJI staking pool holds two independent positions per account: a\nbonded one (manually-claimable USDC revenue) and an auto-compounding one\nbacked by the sRUJI receipt. The staking API repo\n[…]\neach locale's established withdraw/rewards terms.\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(defi): surface RUJI's bonded and auto-compounding positions as se…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-21T22:01:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "516a0db78aa59e93726f81a80545b6cf4427b572",
          "body": "…866)\n\n* fix(tron): stop overstating the network fee on free native transfers\n\ngetBlockInfo substituted coin.feeDefault (0.1 TRX) whenever the total\ncalculated fee was 0. But a *successfully computed* 0 happens only for a native\ntransfer with sufficient bandwidth, no memo, and an active destination \n[…]\n the decoupled case. Addresses\nCodeRabbit review.\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(tron): block self-send + stop overstating network fee (#4863) (#4…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-21T21:54:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0db93831c5dfb98e8f50e440147a9b323095c760",
          "body": "…(#4860)\n\nThe browser extension added XRPL off-chain message signing for dApps\n(GemWallet signMessage) over the shared MPC custom-message keysign. For a\nSecure (multi-device) Vault an iPhone acting as co-signer must reproduce\nthe initiator's exact message digest, or the derived message-ID diverges\na\n[…]\n against SHA-512-half vectors computed outside Swift, so they\npin cross-platform byte identity rather than re-deriving iOS's own output,\nplus precedence guards against the raw-bytes and EIP-712 paths.",
          "is_bot": false,
          "headline": "feat(keysign): co-sign XRPL custom messages with SHA-512-half digest …",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-20T22:09:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "24f3de91287e29359048b5cee812d7e4e03cc17e",
          "body": "… EVM addresses (#4847)\n\n* fix(send): don't auto-switch chain for ambiguous Terra addresses\n\nTerra and Terra Classic share the bech32 HRP `terra`, so a `terra1…`\naddress decodes cleanly on both networks and carries no information about\nwhich one it belongs to. `AddressService.detectChain` resolved i\n[…]\non about the address. A\nvault holding both Terra chains still gets LUNA-or-LUNC decided for it,\nand the caller auto-advances past the chain display; a picker is the real\nfix and is tracked separately.",
          "is_bot": false,
          "headline": "fix(send): switch into the right chain family for ambiguous Terra and…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-20T22:06:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2a35c5244f792b28114535a35a47d2591ab1b8bd",
          "body": "…of dust (#4848)\n\n* fix(send): fill the full balance on Max instead of stranding a digit of dust\n\nCoin.getMaxValue truncated the computed max to decimals - 1, so every Max\nsend left one unit-of-last-place behind. Non-native tokens never reach the\nnative fee-refine path, making a token's Max exactly\n\n[…]\nng all three paths, the\nfull-6-decimal case, and the fee-exceeds-balance guard. Expectations are\nbuilt through the same formatToDecimal the production code uses, so they\nhold on comma-decimal locales.",
          "is_bot": false,
          "headline": "fix(send): fill the full balance on Max instead of stranding a digit …",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-20T22:00:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "84253aa7a60c95432c5fec20825864e7234f219f",
          "body": "* fix(send): fill the full balance on Max instead of stranding a digit of dust\n\nCoin.getMaxValue truncated the computed max to decimals - 1, so every Max\nsend left one unit-of-last-place behind. Non-native tokens never reach the\nnative fee-refine path, making a token's Max exactly\nbalanceDecimal.tru\n[…]\nnloaded sentinel the second test fails, and the cap can\nthen tell the two states apart.\n\nNo production behavior change.\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): size percentage presets by the asset's own precision (#4850)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-20T21:58:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8330df466533479114b8f00221d2c104d40e70b1",
          "body": "…page error (#4852)\n\nWhen THORChain or Maya simulates a swap whose output lands under the minimum-\noutput floor derived from the slippage tolerance, it rejects the quote with a\nbody like \"emit asset 42579895573 less than price limit 340083366993\". That fell\nthrough the classifier to `.serverError(me\n[…]\nalt message.\n\nLocalized in all 8 locales. Tests use the verbatim node bodies captured from\nlive THORChain and Mayanode rejections.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): map the node's price-limit rejection to an actionable slip…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-20T21:50:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9116522494afbd24406bff8caf2662e1330fee9b",
          "body": "…eue + Limit Orders tab (Phases 1–3) (#4816)\n\n* feat(limit-swap): add THORChain limit-swap memo foundation (§0)\n\nPure-logic foundation for THORChain limit swaps (#4232 Phase 1):\n\n- buildLimitSwapMemo: native memo builder for `=<:ASSET:DEST:LIM/INTERVAL/0:AFFILIATE:FEE`.\n- validateLimitSwapInputs: pr\n[…]\nitSwapPayloadAssembler. The real\nreason gasLimit: 0 is safe is that gas/gasLimit are market-swap fee-\ndisplay fields the limit flow never reads.\n\n* refactor(limit-swap): drop limit-mode quote-refresh…",
          "is_bot": false,
          "headline": "feat(limit-swap): track resting limit orders against the THORChain qu…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-20T21:48:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3054c5c26fff87e73bdc8edf98ad4c8335e62e11",
          "body": "* fix(substrate): surface RPC error details\n\nPreserve JSON-RPC error codes and prefer specific data reasons while retaining duplicate broadcast recovery. Remove the unreachable Bittensor catch and cover code 1010 plus message fallback.\n\nCo-Authored-By: Codex <noreply@anthropic.com>\n\n* refactor(rpc):\n[…]\nTransaction) via a shared BroadcastErrorClassifier.broadcastMethods\nset so the class and struct decoders stay in sync. Adds a regression test.\n\n---------\n\nCo-authored-by: Codex <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(substrate): surface RPC error details (#4845)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-20T11:49:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4d020d190500a142f4901465a7eede954da5a3a6",
          "body": "…guarantee (#4834)\n\n* feat(icons): rebuild the icon set on Icons V3, make the compiler the guarantee\n\nReplace Assets.xcassets/Icons wholesale with Icons V3 art under V3 names, and\nchange `Icon` to take an `ImageResource` instead of a `String` so a missing or\nmisspelled icon is a compile error rather\n[…]\nght from V3\n(all single-colour, template). Re-records the CreateVault snapshot for the\nearlier scan/import icon change.\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(icons): rebuild the icon set on Icons V3, make the compiler the …",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-17T23:39:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d3123dbe6ef1103937c272a8b1cd81f613af0acc",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): bump version to 1.42.67 (build 67) (#4833)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-17T01:43:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7a253ac903f1d61fd7fcf39f2d46ce84a56a890c",
          "body": "…4828 — iOS) (#4831)\n\n* fix(assets): align chain-osmo monotone badge with design system\n\nThree fills in the Osmosis chain badge drifted from the design source:\n\n- the flask body used #3D6195 at 70% fill-opacity; it is a solid\n  #3E4A62 in the design\n- the lower-left arc used a literal `black` rather\n[…]\ned-color #02122B, preserves-vector-representation, and\ntemplate-rendering-intent \"original\" so it is never tinted. The symbol's\nframe is 32x32 at the origin, so no coordinate normalization was needed.",
          "is_bot": false,
          "headline": "fix(assets): reconcile monotone chain badge set with design source (#…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-16T23:38:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "798e79f6c328440bf3491b1abd76dbdca8f70fe7",
          "body": "… balance refresh (#4824)\n\n* fix(wallet): refresh per-chain fiat when rates land, not only after a balance refresh\n\nThe VaultMain chain list renders `ChainRowModel.fiatBalance`, a *formatted\nstring* baked when `VaultDetailViewModel.rows` is assigned. Nothing recomputes\nit when a rate arrives: `RateP\n[…]\n the signal must follow the cache, not the write.\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(wallet): refresh per-chain fiat when rates land, not only after a…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-16T23:36:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ee61608c31d8f5fe9ad960372bb1182023a21eea",
          "body": "…in Xcode (#4823)\n\nThe .xcodeproj is gitignored and generated from project.yml via XcodeGen, so\nopening it directly can use a stale (or missing) project. 'make open' runs\ngenerate first, then opens VultisigApp.xcodeproj — one step for newcomers and\nafter any project.yml change.",
          "is_bot": false,
          "headline": "chore(make): add 'make open' target to regenerate + open the project …",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-16T23:26:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "760b210851e9bfe1a92ebaf19cc298f331a252ab",
          "body": "… before the execution condition (#4825)\n\n* fix(limit-swap): honor the source chain the user entered the swap with\n\nEntering Swap from THORChain chain detail preselected THORChain on the\nMarket tab, but switching to Limit silently switched the source to BTC.\n\n`preferredLimitSourceChain` prefers a hi\n[…]\niven keyboard accessory is attached to\nthe outer VStack, not to the cards, so reordering siblings cannot resurrect\nthe merged-accessory bug; focus order is tap-driven and follows the new\nvisual order.",
          "is_bot": false,
          "headline": "fix(limit-swap): honor the entered source chain + put asset selection…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-16T23:24:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8864ee983b6cd0d8eb2570bc886534c1ee1492f4",
          "body": "…EVM balance (#4829)\n\n* fix(balances): stop Multicall3 partial failures zeroing EVM balances\n\nA partial Multicall3 failure silently persisted a 0 balance over a funded\ncoin. `aggregate3` is called with allowFailure = true, so an individual\nsub-call returning success = false does NOT throw — the batc\n[…]\nive\nbatch with a deliberately reverting sub-call.\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(balances): stop a partial Multicall3 failure silently zeroing an …",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-16T23:16:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f470013bd665da0dc9a2607ba27a38f7cbd9165e",
          "body": "…le) (#4818)\n\n* Step 1: bump VultisigCommonData pin to expose SignRipple\n\nBump the commondata Swift package pin from the dest-tag commit\n(2b92938) to c91f2ea, which adds `SignRipple { string raw_json }`\nat sign_ripple = 46 in KeysignPayload.sign_data. The new commit is a\nlinear descendant of the des\n[…]\n IOU value so the \"signed\" case matches its name.\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(keysign): co-signer support for XRPL dApp transactions (SignRipp…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-16T23:07:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ef0b96a1708a900c1b5fc23af99ff5353c3c565f",
          "body": "…ake it render on macOS (#4819)\n\n* fix(keygen): point the peer-discovery info pointer at \"Scan QR\" and make it render on macOS\n\nThe animated pointer in the keygen \"Scan the QR on your other devices\"\ninfo pop-up sat over empty space instead of the \"Scan QR\" button it\nexplains, and on macOS it did not\n[…]\ns as a steady\nfaint ring on the \"Scan QR\" button.\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(keygen): point the peer-discovery info pointer at \"Scan QR\" and m…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-16T22:57:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9076a4dcd8d3213f416fda8499b92e88a5bd26ab",
          "body": "* feat(limit-swap): add THORChain limit-swap memo foundation (§0)\n\nPure-logic foundation for THORChain limit swaps (#4232 Phase 1):\n\n- buildLimitSwapMemo: native memo builder for `=<:ASSET:DEST:LIM/INTERVAL/0:AFFILIATE:FEE`.\n- validateLimitSwapInputs: pre-build validation (asset format, expiry hours\n[…]\n safe is that gas/gasLimit are market-swap fee-\ndisplay fields the limit flow never reads.\n\n* refactor(limit-swap): drop limit-mode quote-refresh countdown\n\nLimit orders execute at a fixed target pri…",
          "is_bot": false,
          "headline": "feat(swap): THORChain limit-order Place flow (#4232) (#4319)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-15T23:25:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1bef342ada346eb2e7966a417e6403a1e6156ae6",
          "body": "… warning, success, backup guide) (#4763)\n\n* Step 1: redesign reshare entry screen with Start/Join option cards\n\nReplace the single centered ReshareView with a cross-platform\nReshareScreen matching the new Figma: left-aligned title and subtitle,\ndevices illustration with glow, and Start Reshare / Jo\n[…]\ntead of requiring every co-signer.\n\nCo-Authored-By: Codex <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "feat(reshare): redesign the reshare flow to the new Figma (pre-flight…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-15T00:18:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9b576caeca033dd787b330fa51486dee657a08ec",
          "body": "…E+ mint (#4788) (#4807)\n\n* feat(swap): add dynamic THORChain secured-asset catalog\n\nPhase 1 of secured-asset discovery (#4788). Adds the source-of-truth\ncatalog that later feeds the swap destination picker:\n\n- ThorchainMainnetAPI: new `.securedAssets` endpoint -> /thorchain/securedassets\n- Thorchai\n[…]\nwap): fix SwapCoinSelectionLogic.sort call for static snapshot API\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": "feat(swap): discover THORChain secured assets + same-underlying SECUR…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-15T00:08:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "11726e9ac3a6c24222a8220d5c7c1666dde8e7b8",
          "body": "…#4813)\n\n* perf(swap): stop double reloadCoins on chain tap\n\nTapping a chain in the swap coin picker fired reloadCoins twice: once\ndirectly from onSelect(chain:) and once from the\n.onChange(of: selectedChain) observer that the same assignment triggers.\nEach reload re-runs the full assemble+merge+sor\n[…]\nsCancelled before the memoized fast-path publish.\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": "perf(swap): fix chain-picker jank on rapid back-and-forth switching (…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-14T22:31:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "08ae49b3af82db8879fa1e2abdcea40f76565001",
          "body": "iOS shipped only TRX + USDT on Tron; the desktop / SDK knownTokens\nregistry lists four. Add the missing three TRC-20 tokens so users can\nenable them from Choose Tokens without adding each as a custom token.\n\n- USDC   TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8   6dp  usd-coin\n- USDD   TXDk8mbtRbXeYuMNS83CfKP\n[…]\nisig-sdk packages/core/chain/coin/knownTokens. usdd & stusdt logos\nported from the shared core coin assets (usdc already present).\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tron): add USDC, USDD & stUSDT tokens (desktop parity) (#4812)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-14T22:21:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1bf10ed5fe551db9da42439395290d3e8050a42b",
          "body": "* fix(defi): render cached Tron details immediately\n\n- hydrate dashboard balances and resources from warm cache\\n- defer portfolio balance refresh until detail data is populated\\n- cover Tron view model response mapping\\n\\nCo-Authored-By: Codex <noreply@anthropic.com>\n\n* fix(defi): align Tron dashbo\n[…]\nhboard matches the THORChain layout on iOS and macOS.\n\n* fix(defi): reduce Tron dashboard top inset\n\nRemove the stacked Screen top padding and use the same 16-point content inset across iOS and macOS.",
          "is_bot": false,
          "headline": "fix(defi): render cached Tron details immediately (#4809)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-14T22:12:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c74e59ec1b7f3b1212a6c89d326a7958aa64e18f",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): bump version to 1.42.66 (build 66) (#4810)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-14T05:36:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5209127eb522161b5b29511c0a190a09ca4e255a",
          "body": null,
          "is_bot": false,
          "headline": "update gitignore",
          "author_name": "Johnny Luo",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-14T05:00:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c61c0cfe68224c78b733034c38fee4c99b56338f",
          "body": "Restore the missing localized peer discovery guidance across all supported locales.\n\nCo-authored-by: Codex <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: restore peer discovery info description (#4808)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-13T23:39:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "35c26a255c7143d6e967208b4674f8695ca8dfa4",
          "body": "Prevent completed cards from retaining the in-progress layout when SwiftUI reuses a row, and cover the expansion policy with unit tests.\n\nCo-authored-by: Codex <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(history): derive transaction card expansion state (#4803)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-13T22:21:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6adb89efa8cccce42784422bb375f7a58bf1f30a",
          "body": "…ance (#4794) (#4797)\n\n* fix(defi): read Staked RUJI amount from on-chain x/staking-x/ruji balance\n\nThe DeFi Staked RUJI card read the staked amount from the Rujira staking\nAPI's `bonded.amount`, which can return 0 even when the vault holds sRUJI\nreceipt tokens on-chain — so the card showed `0 RUJI`\n[…]\nlve tests to match the convention (Codex review).\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(defi): read Staked RUJI amount from on-chain x/staking-x/ruji bal…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-13T17:22:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0d501352201db9c0907949834fc99e8b6f0e050f",
          "body": "… (#4796) (#4798)\n\n* fix(solana): gate signAllTransactions N>1 before the keysign ceremony\n\nSolanaHelper.getPreSignedImageHash looped over all\nsignSolana.rawTransactions, so a multi-transaction Solana batch\n(signAllTransactions, N>1) relayed to an iOS co-signer ran the full\nmulti-device keysign cere\n[…]\nas a co-signer. Comment only; no\nbehavior change.\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(solana): gate signAllTransactions N>1 before the keysign ceremony…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-13T11:31:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bc23cde2467a3e7c043066e005f27eb72b136688",
          "body": "…799)\n\n* feat(defi): curated bRUNE / ybRUNE tokens + liquid-bond contract\n\nAdd first-class Rujira bRUNE (Bonded RUNE, x/brune, 8dp) and its\nauto-compounding staking receipt ybRUNE (x/staking-x/brune, 8dp) as\ncurated TokensStore entries, plus the rujira-staking liquid-bond\ncontract constant.\n\n- Token\n[…]\nisting iOS idiom where sRUJI reuses xruji's logo.\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(defi): bRUNE / ybRUNE curated tokens + stake/unstake (#4778) (#4…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-13T11:13:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "11ceae3a5902ed48fb57856529f5c91e99f5c66c",
          "body": "…cate unknown vouchers (#4792)\n\n* Step 1: add modern IBC /denoms endpoint + CosmosIbcDenom model\n\nAdds CosmosAPI.Endpoint.ibcDenom(hash:) mapping to the modern ibc-go\nGET /ibc/apps/transfer/v1/denoms/{hash} path, which Terra Classic LCDs\nimplement (unlike the deprecated denom_traces path). Adds a Co\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 TerraClassic IBC token display: resolve to symbol/icon/fiat, trun…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-13T11:12:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "74e47d990d2e3da8c5daa0f993c505637981d931",
          "body": "… (#4790)\n\nThe broadcast error classifier mapped several non-duplicate rejections to\nthe duplicate-broadcast sentinel, which KeysignViewModel converts to a\nlocally computed hash and reports as success. A bare \"known\" matched every\n\"unknown ...\" message, \"nonce too high\" is a nonce gap (tx not accept\n[…]\nand\nRpcService (substrate, backing Polkadot + Bittensor). Collapse both into a\nshared BroadcastErrorClassifier that matches only true duplicate signals.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(broadcast): stop dup-sentinel over-matching rejections as success…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-13T10:29:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ef48729cca10c60aa0370b61a68bf949ea7f446b",
          "body": "Base was excluded since KyberSwap's introduction with no documented\nreason. The SDK live-confirmed Kyber on Base and iOS's KyberSwapService\nalready maps .base -> \"base\", so this is a registry-only change.\n\nCloses #4793\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Enable KyberSwap on Base (#4795)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-12T09:49:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f9db7a52ac021ad76497453a5fc7a06d8723d063",
          "body": "* Slide address book selector background with the selection\n\nThe Send address-book picker's list selector was a hand-rolled two-button\nHStack where each cell drew its own background from an isSelected flag, so\nanimating the toggle just cross-faded the two static backgrounds on/off —\nthe highlight sw\n[…]\nt - 1 == -1); behavior unchanged for >= 1 option.\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": "Slide address book selector background with the selection (#4780)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-10T23:15:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8010648685d8b13ff14291d1d00618816cf1aa76",
          "body": "… lookup error (#4791)\n\nfetchTokenAssociatedAccountByOwner already derives the classic-SPL and\nToken-2022 ATAs and confirms them via getAccountInfo when\ngetTokenAccountsByOwner returns an empty result (the common indexer-lag\ncase right after an ATA is created). But when the primary\ngetTokenAccountsB\n[…]\nnely-missing account still yields not-found, and a successful\nprimary lookup returns its account without probing the derived ATAs.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(solana): fall back to ATA derivation on a transient token-account…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-10T22:30:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b6b269f37bd7c5e0eef02bc1e3044ba22bc79eee",
          "body": "… numeric fields (#4784)\n\nA keysign payload is untrusted data deserialized from a co-signer at the\nstart of a ceremony. BlockChainSpecific(from:) decoded chain-specific\nnumeric string fields with the trapping BigInt(stringLiteral:) initializer,\nwhich crashes on any non-numeric or empty string. A bug\n[…]\nmed (incl. explicit \"0\") compute_limit and priority_fee\nfor Solana, plus malformed-field cases for EVM and Polkadot.\n\ncloses #4782\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "[Fix] Harden BlockChainSpecific decoding of untrusted keysign payload…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-10T22:24:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fd0d9f6bc45b4409883a61a8007a83606b98175e",
          "body": "…al FAILED (#4789)\n\nTransient transport failures were mapped to .failed, which the status\npoller treats as terminal and isAlreadyOnChain treats as conclusive\nnegative evidence — a single network blip could permanently mark a live\nTHORChain/Maya tx as FAILED and poison the duplicate-broadcast net.\n\nN\n[…]\nling and\nthe duplicate-broadcast check keeps retrying. 429/5xx still map to\n.failed to surface the error; 404 stays .notFound.\n\nCovers Maya too — both route through THORChainTransactionStatusProvider.",
          "is_bot": false,
          "headline": "fix(thorchain): don't return timeout/network Midgard errors as termin…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-10T22:19:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "293b1a60075020452cf382a450a14ab460c03313",
          "body": "…68) (#4777)\n\n* Inline the Done overview into SigningKeysignScreen with a crossfade\n\nMake SigningKeysignScreen a single mounted container: a ZStack keyed on\ncoordinator.keysignFinished that renders KeysignView while signing and\ncrossfades in place to the flow's DoneScreen (SendDoneScreen/SwapDoneScr\n[…]\new (broadcasted + confirmed) to iterate the feel.\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": "Unify keysign progress + overview into one crossfading container (#47…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-09T22:45:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4e99b1ce4d935981241b84477383993ca45d9957",
          "body": "…dows (#4776)\n\nCosmos-family chains (Cosmos SDK, THORChain/Maya) sign the sha256 of a\ncustom message (Keplr ADR-36 signArbitrary over the StdSignDoc bytes),\nbut keysignMessages fell through to the keccak256 branch for them. The\nresulting digest — and the message-ID the relay derives from it —\ndiverg\n[…]\nustomMessageHex.ts: cosmos-family -> sha256, EdDSA -> raw,\neverything else (EVM, Tron) -> keccak256. EVM/EdDSA/Cardano/typed-data\nbehavior is unchanged.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): sha256-hash cosmos custom messages to match Android/Win…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-09T22:15:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bb3f0c27e198f2ff0e79f87dc1c601bf11be4854",
          "body": "…+ one keysign route/screen (#4775)\n\n* Step 1: FastVaultKeysignBootstrap off-screen session helper + unit tests\n\nAdds FastVaultKeysignBootstrap, which runs the fast-vault relay-session\nbootstrap (register -> wake -> await peer -> kickoff) off-screen and\nassembles the finished KeysignInput. Built on \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": "Unify the keysign screen: fold fast-vault bootstrap into KeysignView …",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-09T00:22:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4ceedc97ff46b53c35d631cd441dccc9c95333cf",
          "body": "…te Continue (#4765)\n\nExtract the XRP destination base-reserve check out of SendDetailsViewModel\nbehind a chain-agnostic `SendAmountValidator` protocol (an input snapshot ->\n`.ok` / `.invalid(message:blocksContinue:)`), implemented for XRP by\n`RippleDestinationReserveValidator` under Blockchain/Ripp\n[…]\nrTests proving the generic\n  wiring blocks Continue independent of any chain.\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": "feat(send): generic SendAmountValidator + animate inline warning + ga…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-09T00:10:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "69441d2d7992d6e61560b0b29a7b738beb95031a",
          "body": "* feat(done): expand transaction details in place instead of pushing\n\nExtract the detail rows from SendCryptoSecondaryDoneView into a reusable\nheader-less/button-less TransactionDetailsCard that owns the\nadd-to-address-book flow, then convert DoneScreen's default\nDoneDetailContent slot to reveal tha\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": "Expand transaction details in place on the Done screen (#4767) (#4772)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-08T23:40:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "de097bfcac23cf094dd628c0f2f1cdffbb37b1b0",
          "body": "…emo & tag+memo support (#4749)\n\n* feat(ripple): hand-rolled XLS-5d X-address codec pinned to canonical vectors\n\nXRPL X-addresses bundle a classic account ID with an optional 32-bit\ndestination tag. WalletCore validates and signs them inside its Ripple\nsigner but exposes no Swift codec, so autofilli\n[…]\nsts don't wire (RequireDest is covered in the threading tests).\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(ripple): XRP Destination Tag as a first-class field + restored m…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-08T22:29:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b042ca975a65a8a2bf6c57c116c6bc5ac2ee172b",
          "body": "…n base reserve (#4764)\n\n* refactor(ripple): extract owner-aware reserve math into RippleReserve\n\nPull the reserve computation getBalance did inline (reserve_base +\nOwnerCount x reserve_inc, seeds on missing server_state fields) into a\npure RippleReserve enum, sibling to RippleFee, and delegate getB\n[…]\nd it to stay exhaustive.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>\nCo-authored-by: Johnny Luo <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "feat(ripple): inline send-form validation of XRP amount vs destinatio…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-08T00:11:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "00279c68c5994106fe82fc7394e12ac13184057d",
          "body": "…nted static 1 XRP (#4748)\n\n* refactor(ripple): extract owner-aware reserve math into RippleReserve\n\nPull the reserve computation getBalance did inline (reserve_base +\nOwnerCount x reserve_inc, seeds on missing server_state fields) into a\npure RippleReserve enum, sibling to RippleFee, and delegate g\n[…]\nlled fee calc now also aborts quietly instead of surfacing a transport\nerror.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ripple): owner-aware reserve for MAX send — remove the double-cou…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-07T23:14:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5f145f9cba2fbf4a16903e2fc0538e76128713b0",
          "body": "…ite (#4736)\n\n* test(figma-parity): reusable Figma-parity comparator + hermetic self-test\n\nAdd VultisigAppTests/FigmaParity/: FigmaParityComparator renders a SwiftUI\nview at exact px via ImageRenderer, diffs it against a committed Figma\nexport, and emits similarity + perceptual (1 - meanDelta) score\n[…]\nhe unchanged committed\nreference PNG, so no reference regeneration is needed.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(figma-parity): reusable Figma-parity harness + /figma skill rewr…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-07T23:00:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "21757eceb1f7b03deb2d0dccf9b71408c94ead43",
          "body": "…alidation on the signed-fee source of truth (#4699)\n\n* fix(swap): co-signer network fee uses signed route gas, not the gasLimit floor\n\nOn a co-signed EVM aggregator swap (SwapKit/1inch/LiFi/Kyber ETH->token) the\nco-signer's Network fee under-displayed ~6-9x less than the vault actually pays\n(shows \n[…]\nture change\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>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(swap): unify EVM swap network fee across initiator, co-signer & v…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-07T22:51:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b2cfe10d8a01ece3a11d53dd2bb8e8c6b8056b80",
          "body": "…matches the signed fee (#4762)\n\nTerra Classic prices its fee as `gasLimit × price (+ burn tax)`. The\ninitiator now simulates a dynamic per-tx gas limit (CosmosSpecific.gas_limit)\nand the signer signs that relayed `gas_wanted`, but `chainSpecific.gas` was\nstill priced at the fixed 300k limit. The si\n[…]\neeps its own\nsigner-side re-derivation (same latent display gap, separate follow-up).\n\nTests updated: baseGas scaling per denom, and the signer echoing the priced\n`gas` verbatim under a relayed limit.",
          "is_bot": false,
          "headline": "fix(terraClassic): price send fee at the dynamic gas limit so Verify …",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-07T22:32:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b4fbda6dac33f264a38eb71bedad648cae617e7e",
          "body": "…locked) (#4754)\n\n* Step 1: retry XRPL requests on transient node errors (same-host, no fallback)\n\nAdd a bounded same-host retry at the Ripple request layer. The default XRPL\nhost (xrplcluster.com) is a load-balanced pool; some backends run stale rippled\nand answer amendmentBlocked (HTTP 200 with re\n[…]\n, each\nwithout retrying.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>\nCo-authored-by: Johnny Luo <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(ripple): retry XRPL requests on transient node errors (amendmentB…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-06T23:26:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "38b21d20730fe8da9469a8f5e70c54681140141d",
          "body": "…P txs (#4750)\n\n* feat(ripple): add SHA-512Half XRP transaction-hash helper\n\nAdd RippleHelper.signedTransactionHash(signedBlob:), computing the\ncanonical XRPL transaction identifying hash: SHA-512Half of the\n0x54584E00 (\"TXN\\0\") prefix + the serialized signed blob, rendered as\nuppercase hex. Pure fu\n[…]\ntput bytes; the\nsigning input, pre-image, and TSS/keysign flow are unchanged.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ripple): compute the deterministic transaction hash for signed XR…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-06T22:57:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cdcdc820c2b597d8875465b3c705be0d3d1ea11d",
          "body": "…already-submitted results (#4746)\n\n* feat(ripple): classify XRPL submit engine results; gate broadcast on tesSUCCESS\n\nThe XRPL submit endpoint echoes tx_json.hash for every engine result, so\nthe previous hash-presence gate reported rejected submits (tem/tef/tel/\nter/tec engine results) as successfu\n[…]\natusProvider semantics, and an injectable\nbackoff so tests run without delay.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ripple): gate broadcast on tesSUCCESS + verify-by-hash dedup for …",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-06T22:32:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "40f4905f82e51cd3bc58a83830217c6ead14e88a",
          "body": "…lection gating, cache-first seed heal (#4745)\n\n* fix(defi): gate the Solana staking card on the position selection\n\nThe Solana stake segment rendered its full staking card for every\nvault, ignoring the per-vault position opt-in that THOR/Maya/Cosmos\nstaking honors — a vault that never selected the \n[…]\nel heal-then-seed\n(first entry can't seed, refresh heals, a fresh VM paints).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(solana): staking DeFi fixes — validator 520 fallback, position-se…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-06T22:24:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "38f0d6e0aefb0e415decbf3188be826555dca5f0",
          "body": "…738)\n\nOn the swap Join Keysign screen the \"To\" row showed keysignPayload.toAddress,\nwhich for a swap is the provider's router/inbound contract — not a user-facing\ndestination. Surface a \"To\" address only when the user directed the swap output\nto an external recipient (an address other than their ow\n[…]\ntion share one parser and one notion\n  of address equality.\n- KeysignSwapConfirmView shows the external recipient instead of the raw router\n  toAddress.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): don't show router address as To on join keysign screen (#4…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-06T11:59:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e5c249e2ff63a2a5539cb48aca00753f5b78c5e5",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): bump version to 1.41.65 (build 65) (#4737)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-04T02:00:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7ca8b30bff2c8aa0766a5db81a70462b20ce90a6",
          "body": "…re (#4735)\n\n`TssKeysignResponse.getSignature()` builds an Ed25519 signature by reversing\n`r` and `s` (big-endian scalars from TSS) into little-endian and concatenating\nthem into R || S. It never left-padded the halves to 32 bytes.\n\ntss-lib emits `r`/`s` via Go's `hex.EncodeToString(bigInt.Bytes())`\n[…]\nh rebuilds bit-for-bit and\nverifies. Updates the custom-message EdDSA tests, which had pinned the old\nun-padded output using toy 2-byte values.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): pad EdDSA r/s to 32 bytes before assembling the signatu…",
          "author_name": "Danial",
          "author_login": "DanialV",
          "committed_at": "2026-07-04T00:59:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8e47a673980f59cef4f12d7a98f2eb783143eb47",
          "body": "…sic (#4733)\n\n* feat(cosmos): add CW20 token_info metadata query to the Cosmos resolver\n\nAdd a `{\"token_info\":{}}` wasm smart-query path so CW20 contract metadata\n(name, symbol, decimals) can be resolved from the chain's LCD — the same\nlookup the SDK/extension perform in getCw20MetaFromLCD:\n\n- Cosmo\n[…]\neview feedback on the PR.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "feat(wallet): support adding custom CW20 tokens on Terra / Terra Clas…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-04T00:36:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "90346ca51284e662ff41d3da21f1d159353cfb83",
          "body": "…' while providers load (#4732)\n\n* fix(swap): publish local token list before awaiting destination providers\n\nThe destination \"Select asset\" picker rendered \"No result found.\" with an\nempty search query until every remote destination-token provider returned.\nThe cached fetch path clears the spinner \n[…]\ne test hermetic); cold-cache\nsource-side publishes once without the registry.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): destination asset picker no longer shows 'No result found.…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-04T00:20:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e73a6ac1b5f5062cb2476bddf72e7c79f69c9032",
          "body": "Vault Settings -> Rename accepted a cleared text field: Save stayed\nenabled and persisted the empty string, leaving the vault with a blank\nname in Vault Details and the home vault selector.\n\nReuse the vault-creation validation path instead of a rename-only rule:\n\n- VaultNameValidator now trims white\n[…]\nng a duplicate entry to folders).\n- No new user-facing strings: enterVaultName and vaultNameExists\n  already exist in all locales.\n\nCloses #4729\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(vault): reject empty/whitespace vault names in Rename Vault (#4731)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-04T00:14:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "39eced8060738ba87f6fba0d34d8edfd3b3e9305",
          "body": "* feat(zcash): add ZIP-317 conventional fee math\n\nByte-parity port of the SDK's zip317.ts (packages/core/chain/chains/utxo/\nfee/zip317.ts, landed in vultisig-sdk#773): conventional fee = 5,000 zats\nper logical action with a two-action grace window, where logical actions =\nmax(ceil(tx_in bytes / 150)\n[…]\n. Regression tests pin the Maya-shaped decode\nand the nil-flag gate behavior.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(zcash): re-plan memo txs to the ZIP-317 conventional fee (#4728)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-04T00:07:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "85b23be375e83afd3653398abdba037fb0c562a1",
          "body": "…re 4.7.0 auxiliaryData) (#4709)\n\n* feat(cardano): canonical CIP-20 memo CBOR encoder (pre-stage for #4708)\n\nAdd a pure, dependency-independent CIP-20 transaction-metadata encoder\n(label 674) that produces canonical CBOR { 674: { \"msg\": [chunks] } } with\n64-UTF-8-byte, codepoint-boundary chunking an\n[…]\neeA*auxLen.\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>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "feat(cardano): attach send memo on-chain as CIP-20 metadata (WalletCo…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-03T23:55:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "617d6f9b5e830b7bc8552aaa9b1a760c6f894bcf",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): bump version to 1.41.64 (#4725)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-03T00:54:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0fa0df6d5415866d7bdc9a4272c54338f9d80cd6",
          "body": "…ed gas limit (#4692)\n\n* fix(cosmos): enforce dynamic Akash fee floor for send + staking + dApp signing\n\niOS hard-coded the Akash fee at 3000 uakt, below Akash's own 0.025 uakt/gas\nnode minimum (5000 uakt at the 200k gas limit), so an ordinary send could be\nrejected on-chain with \"insufficient fee\".\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): dynamic Akash/Cosmos fees — safe floor + simulate-deriv…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-02T22:54:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b4ecf979b1d812f3fc58f820d087e0ad67dd33ad",
          "body": "…ocal Network check + error/retry + iPad back button) (#4722)\n\n* fix(keygen): detect Local Network permission on iPad join, add error + escape hatch\n\nJoining a Local-mode (Bonjour/LAN) keygen on iPad hung forever on\n\"Discovering\" when iOS Local Network access was denied (or Wi-Fi / AP\nclient-isolati\n[…]\nare form; NetService keeps the trailing-dot form.\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(keygen): iPad local-mode join no longer hangs on \"Discovering\" (L…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-02T22:42:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1d7ad62eb8b7073bfd9362032345b1dcc5f8422d",
          "body": "…r) (#4720)\n\n* feat(keysign): show fiat value on the co-sign send amount\n\nThe co-sign \"Send overview\" (\"Join transaction signing\") screen renders\nthrough the shared SendCryptoVerifySummary model + HeroCoinAmount, both of\nwhich carried fiat for the network fee but not for the amount. A co-signer\nsaw \n[…]\niat case (no\norphan gap). Previews updated to carry amountFiat.\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(keysign): show fiat value on the send amount (co-sign + initiato…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-02T22:34:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6b62986f8e78438c73ba636e4e3750eaf8af2f1e",
          "body": null,
          "is_bot": false,
          "headline": "chore(deps): bump WalletCore to v4.7.0 (#4721)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-02T01:53:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "160b784b96071602207fd7a411452063a7f1309e",
          "body": "On iPad, the \"Use standard mode\" button (SwitchToLocalLink) at the bottom\nof the keygen Pair screen in local mode sat flush against the bottom edge.\nThe switchLink computed var applied bottom padding only under #if os(macOS),\nso iOS/iPadOS got zero. iPhone is masked by the home-indicator safe area,\n\n[…]\ndding the primary button directly above\n(bottomButton) already uses, while preserving the existing macOS value (24).\n\nCloses #4713\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keygen): pad \"Use standard mode\" link on iPad Pair screen (#4719)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-01T23:24:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b37eca71b0deca425da81155e9a21989b2f9a671",
          "body": "…) (#4718)\n\nThe green checkmark ring rendered with a flat left edge on the Send/Swap\nverify screens. Checkbox draws the ring as a Circle().stroke on a 24x24\nframe; .stroke centers the 1pt line on the path, so ~0.5pt spills outside\nthe frame. The consent-checkbox row sits flush at the left edge of th\n[…]\ninside\nthe 24x24 bounds so it never overflows to be clipped. This fixes the clip\nfor every Checkbox usage without touching layout.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ui): round the consent-checkbox circle on Send/Swap verify (#4715…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-01T23:24:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "208e2b6aea0421f6d325f30d6848b2dbf95b9d63",
          "body": "The ⓘ info icon beside the \"Gas Limit\" label in the advanced-swap Gas\nLimit sub-sheet had no Button, tap gesture, or tooltip, so tapping it\ndid nothing — a fake interactive affordance. Per the maintainer's\ndecision, drop the dead icon rather than wire up a tooltip. With the\nicon gone the wrapping HStack becomes redundant, so collapse it to the\nbare label Text.\n\nCloses #4714\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): remove dead Gas Limit info icon in advanced settings (#4717)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-01T23:23:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cbc76143257eb61b620c857ac17a13adddbead02",
          "body": "…tion (#4711)\n\n* fix(swap): surface THORNode errors + guard secured-asset swap destination (#4321)\n\nSwapping into a THORChain secured asset (e.g. ETH-USDC) surfaced only a\ngeneric error while swapping out worked. Live mainnet testing confirms\nTHORNode requires a thor1... destination for a secured-as\n[…]\nflow and the error-surfacing logic are unchanged.\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): surface THORNode errors + guard secured-asset swap destina…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-01T23:21:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "828155f44deb8321a8a864d6ef5b3a013272b077",
          "body": "…#4704)\n\nMandatory Rule 6: use .foregroundStyle(), not the deprecated .foregroundColor().\nMechanical 1:1 swap across 139 files (378 sites), behavior-identical for Color\narguments (Color conforms to ShapeStyle).\n\nNot changed:\n- foregroundColor(for:isEnabled:) helper funcs in PrimaryButtonStyle/IconBu\n[…]\n of scope (follow-up: migrate to Theme.colors.*).\n\nPart of the iOS code-quality audit (Phase A — convention sweeps).\n\nCloses #4703\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: replace deprecated .foregroundColor with .foregroundStyle (…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-01T23:08:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "67ee4a95aeb85851aa23b19c80e4b69ea2186b1c",
          "body": "…ck) (#4702)\n\nReplace the byte-identical onChange { asyncAfter(0.5) { focusedField = newValue } }\n@FocusState workaround copy-pasted across 10 screens with a single\n.delayedFocus(from:to:delay:) View extension (behavior-identical, default 0.5s delay).\n\nSites: 9 FunctionTransaction screens (Amount, T\n[…]\ngate, TonStake) + Wallet VaultServerBackupScreen.\n\nPart of the iOS code-quality audit (Phase A — convention sweeps).\n\nCloses #4700\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract shared delayedFocus modifier (de-dupe FocusState ha…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-01T23:04:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "16b65f5a8ad3142f92d61f13eae5a8f8558763b4",
          "body": "…705)\n\nThe delegate form hardcoded a 1 SOL minimum active delegation. That value\nis a feature-gate-activated network constant, not a permanent one, and the\nVultisig RPC proxy blocks getStakeMinimumDelegation, so it could not be read\nthrough the normal path.\n\nRead it directly from a public Solana nod\n[…]\ne-parity; it is deliberately NOT routed through the custom-RPC override\n(which would repoint signing/broadcast too).\n\ncloses #4694\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(solana): fetch min-delegation dynamically from a public node (#4…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-07-01T12:29:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "42853ab0f7a22bf5a70da2330694f934f2cfe774",
          "body": "Per-token unit prices below one cent (e.g. LUNC ~$0.00006, USTC ~$0.0054)\nwere displayed as \"$0.00\", hiding the real price from users.\n\niOS keeps the rate full-precision end-to-end (no data-source pre-scaling\nto undo, unlike Android), so this is a pure display-layer change:\n\n- Add Decimal.formatToFi\n[…]\nings are unaffected: a tiny holding still shows \"$0.00\".\nParity with Android's asPrice fix (vultisig-android #5111).\n\nCloses #4688\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tokens): show sub-cent token prices instead of $0.00 (#4701)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-30T23:51:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4be9133c25a444bf450391e3b5b5c18bd0643ef5",
          "body": "* feat(swap): add Jupiter Solana swap provider (Phase 1: routing + quote/swap, no fee)\n\nWire Jupiter as a swap provider for on-Solana token swaps (SOL<->SPL,\nSPL<->SPL). Jupiter is added to the Solana provider list and is Solana-only\nsame-chain: cross-chain pairs drop it automatically via the SwapCo\n[…]\nixture used a\nfee-owner-style value. (CodeRabbit)\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(swap): Jupiter Solana swap provider (#4669) (#4696)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-30T23:09:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "530ed9ff2a7e68b5d8fd69778d6201e32a129ae7",
          "body": "…thdraw) (#4690)\n\n* feat(solana): staking foundation — models + RPC read layer\n\n* feat(solana): validator metadata seam (Stakewiz, swappable)\n\n* feat(solana): delegate (stake) flow\n\n* feat(solana): deactivate (unstake) + withdraw\n\n* feat(solana): move stake / redelegate (guided, cross-epoch)\n\n* feat\n[…]\nng the cache-first paint shipped for the segment.\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(solana): native staking on the DeFi tab (delegate / unstake / wi…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-30T23:08:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c43c8f0301d652d48e4dd036cb339737113fbc93",
          "body": "Removes the unused Share Vault QR feature: the screen, its view model,\nthe QR rendering components, the public-key export model, and the\nnow-unused ImageFileDocument utility. Also removes the Settings toolbar\nentry point, its route/router/builder wiring, and the shareVaultQR\nlocalization keys from all locale files.",
          "is_bot": false,
          "headline": "chore: remove Share Vault QR screen (#4698)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-06-30T02:45:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e01813b36e2fb3d81f4b617eb0480e2955739324",
          "body": "…rrors (#4686)\n\nCompleteness: add 62 missing keys per locale (QBTC claim flow, Cosmos\nstaking errors, Cardano/validator errors, tx status, tier copy); rebuild\nstale Korean (ships in language picker); remove 11 dead renamed keys.\nFix live bug: noUnencryptedVaultsToImport used in code but missing from\n[…]\nan orphan %d.\n\nValidated: plutil-clean, sorted, full key parity, 0 format-spec mismatches.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>\nCo-authored-by: Johnny Luo <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "i18n: fill 62 missing iOS keys, rebuild Korean, fix ~83 translation e…",
          "author_name": "paaao",
          "author_login": "realpaaao",
          "committed_at": "2026-06-30T01:32:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9fd2c76ee863d1749da580b7e114f7e974351dfd",
          "body": "…695)\n\n* feat(qbtc): derive Bitcoin/QBTC claim accounts on the fly (#4679)\n\nThe QBTC claim flow blocked with `.missingCoin` unless both the Bitcoin\nand QBTC chains were already enabled in the vault. Derive the two native\ncoins in-memory from the vault's own keys (the pure, non-persisting\nCoinFactory\n[…]\n enabled,\n  and the derive-when-not-enabled case.\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(qbtc): derive Bitcoin/QBTC claim accounts on the fly (#4679) (#4…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-29T23:16:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "30fb0739143949c709936f5f61f1b116e493456d",
          "body": "…call3 (#4693)\n\n* perf(balance): run price + balance fetching concurrently (#4673)\n\nBalance fetching was gated behind a full price fetch: updateBalances awaited\nfetchPrices(vault:) before the per-coin balance task group ran, so a slow or\nfailing price provider froze all balances even though balances\n[…]\no it fails if balances ever await prices\n  first.\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": "perf(balance): decouple price fetching + batch EVM balances via Multi…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-29T23:10:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f79b92f9497356b7287f3df276777404e9eeb6bc",
          "body": "* feat(banners): global TTL-based promo-banner dismissal\n\nReplace the mixed promo-banner dismissal storage (app-wide permanent\n@AppStorage(\"appClosedBanners\") + per-vault permanent Vault.closedBanners)\nwith one global, per-device store keyed by a stable banner intent id.\n\n- PromoBannerDismissalStore\n[…]\nunder one\n  lock to close the lost-update window.\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(banners): global TTL-based promo-banner dismissal (#4691)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-29T22:58:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8119be05aea4bb627a0882b6c9bf14c7e347a5ae",
          "body": "At zero or insufficient from-balance the swap quote details were hidden\nbehind a blocking error tooltip: updateQuotes assigned the quote then\nthrew balanceError, which set self.error, and SwapDetailsSummary hid the\nwhole provider/fee/price-impact block while SwapDetailsScreen swapped the\nflip button\n[…]\nte is unchanged.\n- Localization: add swapInsufficientTokenBalance (\"Insufficient %@\n  balance\") to all 7 locale files and re-sort.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(swap): show quote details without sufficient balance (#4658)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-29T22:41:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "aff668e475be2db6d1e8d0aa0114910f72b1afe3",
          "body": "… (#4644)\n\n* refactor(defi): generalize yield integration behind DefiYieldProvider\n\nExtract the DeFi-tab USDC-yield integration into a generic, provider-driven\nframework and migrate Circle onto it. Introduces the DefiYieldProvider\nprotocol + factory, shared YieldVault/Deposit/Withdraw shells and vie\n[…]\n-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: Johnny Luo <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "refactor(defi): generalize yield integration behind DefiYieldProvider…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-29T22:35:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1ba1014ca3a93b7251f6b984986265a4c0278e46",
          "body": "…LDSA-44 key (#4685)\n\nGenerating an MLDSA-44 key is a one-time action. The Advanced settings\n\"Post-Quantum Key\" row was always shown; tapping it on a vault that\nalready had the key surfaced an \"already generated\" notice. Hide the row\nentirely once the vault has the key instead.\n\n- Guard dilithiumKey\n[…]\nlt.publicKeyMLDSA44 == nil (matches\n  the existing reshareVaultRow pattern in this screen).\n- Remove the now-unreachable DilithiumAlreadyGeneratedSheet, its state,\n  and its localization keys (en/ko).",
          "is_bot": false,
          "headline": "feat(settings): hide Post-Quantum Key option when vault already has M…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-06-29T10:57:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6e4576c083f4173d9840deeeace5d1c8a90daa34",
          "body": "…684)\n\nThe QBTC claim flow signs its BTC ECDSA round exclusively via DKLS\n(QBTCClaimRoundRunner / QBTCClaimSecureVaultRoundDriver). GG20 keyshares\ncan't take part in that ceremony, so a GG20 vault that reached keysign\nhung and failed with \"DKLS sign message exhaust retries: fail to\ndownload setup me\n[…]\ndView.\n- QBTCClaimEligibilityChecker short-circuits to .ineligible (no network)\n  so the promo banner / Claim button never appear for GG20 vaults.\n- Localize the new title/detail across all 8 locales.",
          "is_bot": false,
          "headline": "fix(qbtc): block GG20 vaults from QBTC claim with a clear message (#4…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-06-29T10:55:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "73124a8e547ac7441a85f8a854efbc51a09fdf29",
          "body": "… (#4675)\n\nLI.FI's estimate.toAmount (dstAmount) is already net of the integrator\nfee, which LI.FI takes from the source token and marks included: true.\nThe ranking branch subtracted it again, understating LI.FI's ranked\nvalue by ~0.5% and flipping provider selection away from LI.FI on\nnear-ties at the in-band preference boundary.\n\nPass dstAmount through unchanged (same as 1inch/Kyber) and update the\nranking test vector that encoded the double-counted value.\n\nCloses #4674",
          "is_bot": false,
          "headline": "fix(swap): stop double-counting LI.FI integrator fee in quote ranking…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-06-28T23:15:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a261fd452fcdbce41ff22a1aedff8aeaa574c6b9",
          "body": "Co-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(assets): use jpg for qbtc coin icon (#4677)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-06-28T00:11:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "85530353727a69e0e25e5f94a31d0d93ec49c2b5",
          "body": "* feat(defi): TON staking on the DeFi tab (#4653)\n\nMove TON nominator-pool staking out of the generic Functions (FunctionCall)\nflow and into a dedicated TON section on the DeFi tab, reusing the same generic\nDefiChain staked-positions screens that THORChain / Maya / Cosmos already use.\n\n- Register .t\n[…]\n from the implementation, not invalid form state.\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(defi): TON staking on the DeFi tab (#4653) (#4654)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-25T22:11:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c1e6151184728ca83c84d6e0e2900e4315d0095e",
          "body": "Render an MLDSA key row in the Keys section of the vault Details card\nwhen the vault has a non-empty publicKeyMLDSA44, reusing the existing\ncopyable vaultKeyRow helper for parity with the ECDSA/EdDSA rows\n(including the shared/exported isForSharing view). The row is hidden\nfor vaults without an MLDSA key.\n\nAdds the \"MLDSA\" localization key to all 7 locale files.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(vault): show MLDSA key in vault details screen (#4651) (#4652)",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-25T21:58:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1917b6a122369d723498cd43432def3145dc4e57",
          "body": "…le pools (#4615) (#4616)\n\n* Add NativePoolAsset model + pool-id parsing for dynamic swap eligibility\n\nPure types + the synchronous eligibility predicate, no I/O. NativePoolAsset\nnormalizes a /pools asset id (CHAIN.TICKER-0XCONTRACT) into {chain, ticker,\nlowercased contract, isAvailable, isTradingHa\n[…]\n the halt gate reflects the network the quote actually deposits on.\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(swap): dynamic THORChain/Maya swap eligibility from live Availab…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-24T23:52:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f62c588e8da5dd78cda2722e0d1b804abe28fc72",
          "body": "…/unfreeze & resources sheet (#4648)\n\n* fix(defi): match Figma + adopt shared staking pattern for TRON freeze/unfreeze & resources sheet\n\n- FilledSegmentedControl: add optional icon/iconSelectedTint to the type\n  protocol (defaulted to nil so ScannerMode is unchanged) and a .filledPill\n  size matchi\n[…]\n-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: Johnny Luo <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(defi): match Figma + adopt shared staking pattern for TRON freeze…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-24T23:31:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f36cb9d3809d7ca4597fdcc1529b57c1ac330de3",
          "body": "…en (#4641)\n\nThe swap keysign confirmation screen showed from/to coin, amounts,\nprovider and fees but had no destination address, so a co-signer\n(non-initiating device) could not verify where funds go before signing.\n\nAdd a read-only destination-address row fed from KeysignPayload.toAddress\n(the pro\n[…]\ng the existing row styling and the localized \"to\" label. Display\nonly; no change to keysign payload construction, TSS, or signing.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): show swap destination address on co-signer confirm scre…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-24T23:05:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cb3347fb38551de4701371eba93b737a3b89acd8",
          "body": null,
          "is_bot": false,
          "headline": "release v1.40.63 (#4646)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-06-24T00:10:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "34f0ac8f509dad5dc671213aa1105b5a0de1f658",
          "body": "…s (#4645)\n\nLiFi swaps sourced from Solana omitted the integrator/fee params because\n`Coin.isLifiFeesSupported` only returned true for EVM chains. That left\nSolana routes uncharged while the UI still computed and displayed a ~0.5%\nfee that was never collected, and denied VULT holders their tier disc\n[…]\n.\nEVM-source routes (including Cronos/Hyperliquid) already charged the fee\nand are unaffected.\n\nAdds LiFiFeesSupportedTests pinning EVM + Solana as fee-charging and\nnon-LiFi source chains as excluded.",
          "is_bot": false,
          "headline": "fix(swap): charge VULT-discounted LiFi integrator fee on Solana route…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-06-23T23:20:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0e50592598dfe5dc8cfe38086f58e7f3a4e7662e",
          "body": "…en catalog refresh-on-open (#4643)\n\n* fix(swap): SwapKit provider gate fail-closed on cold cache miss + token catalog refresh-on-open\n\nTwo SwapKit cache reliability fixes.\n\nProvider gate: SwapKitProviderCache.isEnabled(chain:) now fails CLOSED on the\nno-snapshot edge. On a cold launch where the fir\n[…]\nack, pointing to SwapKitProviderCache.isEnabled for the rationale.\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(swap): SwapKit provider gate fail-closed on cold cache miss + tok…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-23T22:27:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4c7af45e5c3829483f5b4c0976b76d3b61360d80",
          "body": "…0bps (#4642)\n\nAmong swap quotes already within the provider-preference band (economically\nequivalent on net destination output), prefer the one with lower source-chain\ngas before applying provider preference — but only when BOTH compared quotes\nexpose gas in the same native-wei unit (same-chain EVM\n[…]\n the preference band from 100bps to 50bps so a \"preferred\"\nprovider can no longer be handed up to 1% (2x the 50bps affiliate fee).\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): in-band lower-gas tie-break + tighten preference band to 5…",
          "author_name": "Gaston",
          "author_login": "gastonm5",
          "committed_at": "2026-06-23T21:52:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "44b3535af42fd9c31fbed169e031fd70f3e583b7",
          "body": "…636)\n\nThe keysign Rive animation exposes a `progessPercentage` bar, but\n`KeysignAnimationView` never bound it — only `KeygenAnimationView` did.\nThe bar therefore stayed empty during signing. For standard Send the\ncoin-logo glow filled that area so it looked populated, but swap and\ncustom-message fl\n[…]\ny\n- SendCryptoKeysignView: pass-through `progress` parameter\n- KeysignView: feed `viewModel.signingProgress` into the signing view\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): fill signing progress bar for swap & custom message (#4…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-06-23T21:46:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4089931199b42ed60df8d5349328816c4173c20c",
          "body": "…erance-v2\n\nfix(swap): default THORChain tolerance_bps to 0 so Auto swaps aren't rejected",
          "is_bot": false,
          "headline": "Merge pull request #4640 from vultisig/fix/thorchain-swap-auto-no-tol…",
          "author_name": "paaao",
          "author_login": "realpaaao",
          "committed_at": "2026-06-23T14:26:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 100,
      "commits_last_year": 1740,
      "latest_release_at": "2026-07-17T01:06:25Z",
      "latest_release_tag": "v1.42.67",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 52,
      "days_since_latest_release": 5,
      "mean_days_between_releases": 4.6
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 62,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 22,
      "stars": 40,
      "watchers": 4,
      "fork_history": {
        "days": [
          {
            "date": "2024-03-17",
            "count": 1
          },
          {
            "date": "2024-05-22",
            "count": 1
          },
          {
            "date": "2024-06-12",
            "count": 1
          },
          {
            "date": "2024-06-18",
            "count": 1
          },
          {
            "date": "2024-07-29",
            "count": 1
          },
          {
            "date": "2024-09-04",
            "count": 1
          },
          {
            "date": "2024-10-08",
            "count": 1
          },
          {
            "date": "2024-12-18",
            "count": 1
          },
          {
            "date": "2025-02-14",
            "count": 1
          },
          {
            "date": "2025-03-15",
            "count": 1
          },
          {
            "date": "2025-04-19",
            "count": 1
          },
          {
            "date": "2025-05-02",
            "count": 1
          },
          {
            "date": "2025-07-12",
            "count": 1
          },
          {
            "date": "2025-11-15",
            "count": 1
          },
          {
            "date": "2026-03-16",
            "count": 1
          },
          {
            "date": "2026-03-20",
            "count": 1
          },
          {
            "date": "2026-03-25",
            "count": 1
          },
          {
            "date": "2026-04-18",
            "count": 1
          },
          {
            "date": "2026-04-30",
            "count": 1
          },
          {
            "date": "2026-05-01",
            "count": 1
          },
          {
            "date": "2026-05-07",
            "count": 1
          },
          {
            "date": "2026-07-19",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 22,
        "total_forks": 22
      },
      "star_history": {
        "days": [
          {
            "date": "2024-04-18",
            "count": 1
          },
          {
            "date": "2024-04-19",
            "count": 1
          },
          {
            "date": "2024-05-01",
            "count": 1
          },
          {
            "date": "2024-06-16",
            "count": 1
          },
          {
            "date": "2024-07-04",
            "count": 1
          },
          {
            "date": "2024-07-07",
            "count": 1
          },
          {
            "date": "2024-07-10",
            "count": 1
          },
          {
            "date": "2024-08-12",
            "count": 1
          },
          {
            "date": "2024-08-15",
            "count": 1
          },
          {
            "date": "2024-08-20",
            "count": 1
          },
          {
            "date": "2024-08-29",
            "count": 1
          },
          {
            "date": "2024-09-04",
            "count": 1
          },
          {
            "date": "2024-09-07",
            "count": 1
          },
          {
            "date": "2024-09-23",
            "count": 1
          },
          {
            "date": "2025-03-29",
            "count": 1
          },
          {
            "date": "2025-04-19",
            "count": 1
          },
          {
            "date": "2025-04-21",
            "count": 1
          },
          {
            "date": "2025-05-28",
            "count": 1
          },
          {
            "date": "2025-06-13",
            "count": 1
          },
          {
            "date": "2025-07-30",
            "count": 1
          },
          {
            "date": "2025-08-07",
            "count": 1
          },
          {
            "date": "2025-10-14",
            "count": 1
          },
          {
            "date": "2025-10-15",
            "count": 1
          },
          {
            "date": "2025-12-03",
            "count": 1
          },
          {
            "date": "2026-01-25",
            "count": 1
          },
          {
            "date": "2026-02-25",
            "count": 1
          },
          {
            "date": "2026-03-23",
            "count": 1
          },
          {
            "date": "2026-04-08",
            "count": 1
          },
          {
            "date": "2026-04-20",
            "count": 1
          },
          {
            "date": "2026-04-21",
            "count": 1
          },
          {
            "date": "2026-04-30",
            "count": 1
          },
          {
            "date": "2026-05-04",
            "count": 1
          },
          {
            "date": "2026-05-07",
            "count": 1
          },
          {
            "date": "2026-05-19",
            "count": 1
          },
          {
            "date": "2026-05-22",
            "count": 1
          },
          {
            "date": "2026-05-28",
            "count": 1
          },
          {
            "date": "2026-06-03",
            "count": 1
          },
          {
            "date": "2026-06-10",
            "count": 1
          },
          {
            "date": "2026-06-14",
            "count": 1
          },
          {
            "date": "2026-07-21",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 40,
        "total_stars": 40
      },
      "open_issues_and_prs": 23
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 78072,
      "source_files_sampled": 1876,
      "oversized_source_files": 3,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 7403
    },
    "dependencies": {
      "manifests": [
        "VultisigApp/Gemfile"
      ],
      "advisories": {
        "error": null,
        "scope": "repository_graph",
        "source": "osv",
        "findings": [
          {
            "name": "addressable",
            "direct": false,
            "version": "2.8.8",
            "severity": "high",
            "ecosystem": "rubygems",
            "cvss_score": 7.5,
            "advisory_ids": [
              "GHSA-h27x-rffw-24p4"
            ],
            "fixed_version": "2.9.0",
            "advisory_count": 1,
            "oldest_advisory_days": 105
          },
          {
            "name": "faraday",
            "direct": false,
            "version": "1.8.0",
            "severity": "high",
            "ecosystem": "rubygems",
            "cvss_score": 7.5,
            "advisory_ids": [
              "GHSA-33mh-2634-fwr2",
              "GHSA-98m9-hrrm-r99r"
            ],
            "fixed_version": "2.14.3",
            "advisory_count": 2,
            "oldest_advisory_days": 162
          },
          {
            "name": "json",
            "direct": false,
            "version": "2.18.0",
            "severity": "high",
            "ecosystem": "rubygems",
            "cvss_score": 8.2,
            "advisory_ids": [
              "GHSA-3m6g-2423-7cp3"
            ],
            "fixed_version": "2.19.2",
            "advisory_count": 1,
            "oldest_advisory_days": 124
          },
          {
            "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": 4,
          "moderate": 1
        },
        "advisory_count": 6,
        "affected_count": 5,
        "assessed_count": 105,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "rubygems"
      ],
      "dependencies": [
        {
          "name": "fastlane",
          "manifest": "VultisigApp/Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": "2.229.1"
        },
        {
          "name": "ostruct",
          "manifest": "VultisigApp/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": "@cosmjs/crypto",
            "direct": false,
            "version": "0.39.0",
            "ecosystem": "npm"
          },
          {
            "name": "@cosmjs/encoding",
            "direct": false,
            "version": "0.39.0",
            "ecosystem": "npm"
          },
          {
            "name": "@cosmjs/math",
            "direct": false,
            "version": "0.39.0",
            "ecosystem": "npm"
          },
          {
            "name": "@cosmjs/utils",
            "direct": false,
            "version": "0.39.0",
            "ecosystem": "npm"
          },
          {
            "name": "@noble/ciphers",
            "direct": false,
            "version": "2.2.0",
            "ecosystem": "npm"
          },
          {
            "name": "@noble/curves",
            "direct": false,
            "version": "2.2.0",
            "ecosystem": "npm"
          },
          {
            "name": "@noble/hashes",
            "direct": false,
            "version": "2.2.0",
            "ecosystem": "npm"
          },
          {
            "name": "@scure/base",
            "direct": false,
            "version": "2.2.0",
            "ecosystem": "npm"
          },
          {
            "name": "@scure/bip39",
            "direct": false,
            "version": "2.2.0",
            "ecosystem": "npm"
          },
          {
            "name": "base64-js",
            "direct": false,
            "version": "1.5.1",
            "ecosystem": "npm"
          },
          {
            "name": "cosmjs-types",
            "direct": false,
            "version": "0.11.0",
            "ecosystem": "npm"
          },
          {
            "name": "readonly-date-esm",
            "direct": false,
            "version": "2.0.0",
            "ecosystem": "npm"
          },
          {
            "name": "abbrev",
            "direct": false,
            "version": "0.1.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "addressable",
            "direct": false,
            "version": "2.8.8",
            "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.1211.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-sdk-core",
            "direct": false,
            "version": "3.241.4",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-sdk-kms",
            "direct": false,
            "version": "1.121.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-sdk-s3",
            "direct": false,
            "version": "1.213.0",
            "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.8.0",
            "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-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_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.18.0",
            "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.2",
            "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": 105,
        "direct_count": 2,
        "indirect_count": 103
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 3,
        "merged_prs": 2508,
        "open_issues": 20,
        "closed_ratio": 0.991,
        "closed_issues": 2185,
        "closed_unmerged_prs": 133
      },
      "bus_factor": 2,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "enriquesouza",
          "commits": 2519,
          "avatar_url": "https://avatars.githubusercontent.com/u/1700699?v=4"
        },
        {
          "type": "User",
          "login": "johnnyluo",
          "commits": 2199,
          "avatar_url": "https://avatars.githubusercontent.com/u/749608?v=4"
        },
        {
          "type": "User",
          "login": "Rockindash",
          "commits": 1784,
          "avatar_url": "https://avatars.githubusercontent.com/u/13535088?v=4"
        },
        {
          "type": "User",
          "login": "gastonm5",
          "commits": 564,
          "avatar_url": "https://avatars.githubusercontent.com/u/7192634?v=4"
        },
        {
          "type": "User",
          "login": "flypaper0",
          "commits": 545,
          "avatar_url": "https://avatars.githubusercontent.com/u/5384197?v=4"
        },
        {
          "type": "User",
          "login": "realpaaao",
          "commits": 47,
          "avatar_url": "https://avatars.githubusercontent.com/u/167348323?v=4"
        },
        {
          "type": "User",
          "login": "Dolloong",
          "commits": 21,
          "avatar_url": "https://avatars.githubusercontent.com/u/151611992?v=4"
        },
        {
          "type": "User",
          "login": "0x-suzume",
          "commits": 15,
          "avatar_url": "https://avatars.githubusercontent.com/u/265643117?v=4"
        },
        {
          "type": "User",
          "login": "Vaulty-bot",
          "commits": 13,
          "avatar_url": "https://avatars.githubusercontent.com/u/257854823?v=4"
        },
        {
          "type": "User",
          "login": "jpthor",
          "commits": 10,
          "avatar_url": "https://avatars.githubusercontent.com/u/41815753?v=4"
        }
      ],
      "contributors_sampled": 27,
      "top_contributor_share": 0.325
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "objective-c-xcode.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "Gemfile.lock",
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 0,
            "reason": "binaries present in source code",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 5,
            "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": "29 out of 29 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": 8,
            "reason": "Found 26/30 approved changesets -- score normalized to 8",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 4 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 1 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": 10,
            "reason": "all dependencies are pinned",
            "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": 4,
            "reason": "6 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "9fc8f630bcfc6e1947d5b2d07ecf778bdd7fb16e",
        "ran_at": "2026-07-22T03:21:14Z",
        "aggregate_score": 4.3,
        "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-21T23:12:34Z",
      "oldest_open_prs": [
        {
          "number": 4734,
          "created_at": "2026-07-03T18:09:19Z",
          "last_comment_at": "2026-07-03T18:09:48Z",
          "last_comment_author": "coderabbitai"
        },
        {
          "number": 4849,
          "created_at": "2026-07-20T11:25:27Z",
          "last_comment_at": "2026-07-21T15:01:45Z",
          "last_comment_author": "gastonm5"
        },
        {
          "number": 4857,
          "created_at": "2026-07-20T18:52:56Z",
          "last_comment_at": "2026-07-20T18:53:32Z",
          "last_comment_author": "coderabbitai"
        }
      ],
      "last_merged_pr_at": "2026-07-21T22:56:11Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 2122,
          "created_at": "2025-04-30T05:57:01Z",
          "last_comment_at": "2025-04-30T06:04:52Z",
          "last_comment_author": "jpthor"
        },
        {
          "number": 4309,
          "created_at": "2026-05-05T17:04:17Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4325,
          "created_at": "2026-05-07T19:58:54Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4375,
          "created_at": "2026-05-17T17:44:15Z",
          "last_comment_at": "2026-05-18T16:38:28Z",
          "last_comment_author": "gastonm5"
        },
        {
          "number": 4655,
          "created_at": "2026-06-25T15:55:57Z",
          "last_comment_at": "2026-07-05T22:46:33Z",
          "last_comment_author": "johnnyluo"
        },
        {
          "number": 4755,
          "created_at": "2026-07-06T18:51:40Z",
          "last_comment_at": "2026-07-09T03:30:22Z",
          "last_comment_author": "johnnyluo"
        },
        {
          "number": 4756,
          "created_at": "2026-07-06T18:59:52Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4757,
          "created_at": "2026-07-06T18:59:53Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4758,
          "created_at": "2026-07-06T18:59:54Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4760,
          "created_at": "2026-07-07T05:47:51Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4769,
          "created_at": "2026-07-08T13:48:12Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4800,
          "created_at": "2026-07-13T11:20:46Z",
          "last_comment_at": "2026-07-13T23:40:29Z",
          "last_comment_author": "johnnyluo"
        },
        {
          "number": 4817,
          "created_at": "2026-07-15T17:19:06Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4838,
          "created_at": "2026-07-18T05:51:06Z",
          "last_comment_at": "2026-07-21T14:50:12Z",
          "last_comment_author": "gastonm5"
        },
        {
          "number": 4846,
          "created_at": "2026-07-20T07:22:22Z",
          "last_comment_at": "2026-07-20T09:54:16Z",
          "last_comment_author": "realpaaao"
        },
        {
          "number": 4853,
          "created_at": "2026-07-20T12:59:46Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4854,
          "created_at": "2026-07-20T12:59:48Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4856,
          "created_at": "2026-07-20T18:24:57Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4858,
          "created_at": "2026-07-20T19:33:35Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4861,
          "created_at": "2026-07-21T06:46:27Z",
          "last_comment_at": "2026-07-21T06:49:37Z",
          "last_comment_author": "realpaaao"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/vultisig/vultisig-ios",
    "host": "github.com",
    "name": "vultisig-ios",
    "owner": "vultisig"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 68,
      "inputs": {
        "security": 54,
        "vitality": 96,
        "community": 48,
        "governance": 73,
        "engineering": 61
      },
      "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": 1740,
              "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": "1740 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 1740
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 1 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.42.67",
              "releases_from_tags": false,
              "days_since_latest_release": 5,
              "mean_days_between_releases": 4.6
            },
            "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 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~4.6 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 4.6
                    }
                  }
                ],
                "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": 48,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "forks": 22,
              "stars": 40,
              "watchers": 4,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "below_threshold"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "40 stars",
                "points": 25.8,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 40
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "22 forks",
                "points": 11,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 22
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "4 watchers",
                "points": 2.7,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "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": 73,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "moderate",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 64,
            "inputs": {
              "bus_factor": 2,
              "contributors_sampled": 27,
              "top_contributor_share": 0.325
            },
            "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 32% of commits",
                "points": 15.2,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 32
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "27 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 27
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 4 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "excellent",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 95,
            "inputs": {
              "merged_prs": 2508,
              "open_issues": 20,
              "closed_issues": 2185,
              "issue_closed_ratio": 0.991,
              "closed_unmerged_prs": 133
            },
            "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": "2508/2641 decided PRs merged",
                "points": 36.3,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 2508,
                      "decided": 2641
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 26/30 approved changesets -- score normalized to 8",
                "points": 12,
                "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": "moderate",
        "name": "Engineering Quality",
        "value": 61,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "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": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "29 out of 29 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 54,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "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": 43,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 4.3
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "binaries present in source code",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 3.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "29 out of 29 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 26/30 approved changesets -- score normalized to 8",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 4 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 1 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": "all dependencies are pinned",
                "points": 5,
                "status": "met",
                "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": "6 existing vulnerabilities detected",
                "points": 3,
                "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 105 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": 105
                }
              },
              {
                "code": "advisories_repo_graph_caveat",
                "params": {}
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "source": "osv",
              "advisories": 6,
              "affected_packages": 5,
              "assessed_packages": 105,
              "unassessed_packages": 0,
              "affected_by_severity": "high 4, 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": 105,
              "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": 5
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "excellent",
        "name": "AI Readiness",
        "value": 86,
        "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": 0.99,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 7403
            },
            "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": "99 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 99,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 81,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "Gemfile.lock",
                "package-lock.json"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.77,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Swift (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Swift"
                    }
                  }
                ],
                "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": "77 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 77,
                      "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": "all dependencies are pinned",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Swift",
              "largest_source_bytes": 78072,
              "source_files_sampled": 1876,
              "oversized_source_files": 3
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Swift (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Swift"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "3/1876 source files over 60KB",
                "points": 54.9,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 1876,
                      "oversized": 3
                    }
                  }
                ],
                "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:22:11.840475Z",
  "schema_version": "0.26.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/v/vultisig/vultisig-ios.svg",
  "full_name": "vultisig/vultisig-ios",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

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

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

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