Публічний реєстр
Звіт про здоров'я програмного забезпеченнясхема 0.26.0 · метрики 1.13.0 · 2026-07-22 03:22 UTC

vultisig / vultisig-ios

Vultisig iOS App

SwiftApache-2.0★ 40 зірок⑂ 22 форкиз січ. 2024 р.Переглянути на GitHub ↗

vultisig/vultisig-ios має індекс здоров’я 68 зі 100, що відповідає смузі «Помірний». Найвищий показник — Vitality (96/100), найнижчий — Community & Adoption (48/100). Останнє оновлення — сьогодні. Більшість нещодавньої роботи виконують 2 учасники.

68
загалом / 100
Помірний

Індекс здоров'я програмного забезпечення

Метрики згруповано у зважені категорії на шкалі 1–100. Загальна оцінка починається як їхнє середнє; коли публічні дані активують Політику юрисдикцій високого ризику, рейтинг коригується й отримує верхню межу 49 («Під ризиком»). Готовність до ШІ не входить до індексу.

68
Відмінний85-100Зразковий; відповідає практично всім перевіреним критеріям
Добрий70-84Здоровий; незначні прогалини
Помірний50-69Прийнятний, але з помітними прогалинами; рекомендовано перевірку
У зоні ризику30-49Суттєві слабкі місця; впровадження потребує обережності
Критичний1-29Серйозні проблеми (покинутий, єдиний мейнтейнер, без базової гігієни)
ЖиттєздатністьСпільнота тавпровадженняСталість таврядуванняІнженернаякістьБезпекаГотовність доШІ

Профіль оцінок

Кожна вісь — окрема категорія. Форма важить більше, ніж середнє: здоровий об'єкт заповнює всю фігуру, тоді як профіль із піками та провалами означає, що сила в одному вимірі маскує ризик в іншому.

Власність

Vultisig: Secure Crypto VaultОрганізація
132 підписники72 публічні репозиторіїз січ. 2024 р.

За цим репозиторієм стоїть організація — спільна, підзвітна опіка, здатна пережити будь-якого окремого мейнтейнера.

Метрики за категоріями

Життєздатність

Чи живий проєкт — чи пишеться код і чи виходять релізи?

96Відмінний · 22% загального індексу
Як обчислюється оцінка
36/36Свіжість push — останній push 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
Як обчислюється оцінка
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% загального індексу
Як обчислюється оцінка
25.8/60Зірки — 40 зірок
11/25Форки — 22 форків
2.7/15Спостерігачі — 4 спостерігачів
Використані вхідні дані
forks22
stars40
watchers4
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonbelow_threshold
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (Apache-2.0)
0/18Настанови CONTRIBUTING
0/13.5Кодекс поведінки
0/7.2Шаблон issue
6.3/6.3Шаблон PR
Використані вхідні дані
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Вирішення issue — закрито 99% issue
36.3/38.3Прийняття PR — злито 2 508/2 641 вирішених PR
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Охоплення власника — 132 підписників у vultisig
18/25Послужний список — 72 публічних репозиторіїв, вік облікового запису ~2 р.
Використані вхідні дані
followers132
owner_typeOrganization
is_verified
owner_loginvultisig
public_repos72
account_age_days906

Інженерна якість

Чи наявні базові інженерні практики та документація?

61Помірний · 20% загального індексу
Як обчислюється оцінка
24/24Процеси CI — 1 процес(ів) CI
24/24Наявні тести
0/16Конфігурація лінтера
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. Цей репозиторій не публікує пакета, який резолвить індекс, тож натомість оцінено граф залежностей репозиторію. Цей граф змішує закріплені версії для розробки й тестування зі справді постачаними залежностями, тож оцінюються лише задекларовані runtime-залежності; транзитивні знахідки подаються як контекст і в оцінку не входять. Досяжність не аналізується.

Готовність до ШІ

Наскільки репозиторій оснащений для розробки та супроводу за участі ШІ-агентів? Незалежний, експериментальний бейдж — вага 0.0, тож він подається окремо і не впливає на загальний індекс здоров'я.

86Відмінний · 0% загального індексу
Як обчислюється оцінка
45/45Інструкції для агентів — AGENTS.md, CLAUDE.md
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 99 з 100 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share0,99
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes7 403
Як обчислюється оцінка
18/18Розгортання однією командою — Makefile
22/22Автоматизовані тести
0/11Конфігурація лінтера / форматера
11/11Статична перевірка типів — Swift (статично типізована)
10/10Відтворюване середовище — lockfile
10/10Підтверджена практика роботи з агентами — 77 з останніх 100 комітів створено агентом або з його зазначенням
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Керовані розміри файлів — 3/1 876 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languageSwift
largest_source_bytes78 072
source_files_sampled1 876
oversized_source_files3

Ключові факти

40зірок GitHub
27контриб'юторів
1 740комітів за останні 12 місяців
0днів від останнього пушу
100релізів
2бас-фактор
20відкритих issue
RubyGemsпакетних екосистем

Докладніше

Історія зірок і форків 40 ★ / 22 ⇿
40Зірки
22Форки
100Релізи

Коли додано кожну зірку й форк — зібрано з 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 непрямих (транзитивних) пакетів. Транзитивне замикання є повним, коли в репозиторії закомічено lockfile.

РеєстрПакетВерсіяЗв'язок
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 — повна методологія · вікі метрик.

Як окремий результат виглядає на тлі всього реєстру: сукупна статистика.