公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-28 01:11 UTC

metanorma / suma

Management utility for SUMA (STEP Unified Model-Based Standards Architecture)

Ruby未检测到许可证★ 1 星标⑂ 0 复刻始于 2024年6月在 GitHub 上查看 ↗

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

60
总分 / 100
中等

软件健康指数

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

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

评分画像

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

所有权

Metanorma组织
95 关注者331 个公开仓库始于 2018年5月

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布
RubyGemssuma0.5.2-390 天前

按类别列示的指标

活力

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

70良好 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 0 天前
11.1/36提交节奏 — 52 周中有 16 周有提交
18/18提交量 — 最近一年 102 次提交
10/10OpenSSF Scorecard:Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
所用输入
commits_last_year102
human_commit_share1
days_since_last_push0
active_weeks_last_year16

发布纪律

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

社区与采用

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

40存在风险 · 占总体的 18%
评分方式
0/60星标 — 1 个星标
0/25复刻 — 0 个复刻
4.7/15关注者 — 8 位关注者
所用输入
forks0
stars1
watchers8
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

67中等
评分方式
22.5/22.5README
0/22.5许可证 — 未检测到许可证文件
18/18CONTRIBUTING 指南
13.5/13.5行为准则
0/7.2议题模板
6.3/6.3PR 模板
所用输入
has_readme
has_license
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template
评分方式
46.5/80累计下载量 — rubygems 合计历史 29,667 次下载
0/20注册表被依赖数 — 该生态系统不报告此项
所用输入
packagessuma
dependents
ecosystemsrubygems
total_downloads29,667
monthly_downloads
已排除计分(无数据或不适用):注册表被依赖数。 其余权重已重新归一化。

可持续性与治理

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

66中等 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
9.7/22.5提交分布 — 头号贡献者编写了 57% 的提交
6.8/13.5贡献者广度 — 5 位贡献者
10/10OpenSSF Scorecard:Contributors — project has 5 contributing companies or organizations
所用输入
bus_factor1
contributors_sampled5
top_contributor_share0.569
评分方式
36.4/46.8议题解决 — 78% 的议题已关闭
35/38.3PR 接受 — 已裁定的 PR 中 54/59 已合并
0/15OpenSSF Scorecard:Code-Review — Found 0/16 approved changesets -- score normalized to 0
所用输入
merged_prs54
open_issues10
closed_issues35
issue_closed_ratio0.778
closed_unmerged_prs5
评分方式
30/30所有权背书 — 组织持有
0/20已验证域名
14.3/25所有者影响力 — metanorma 有 95 位关注者
25/25既往记录 — 331 个公开仓库,账户约 8 年
所用输入
followers95
owner_typeOrganization
is_verified
owner_loginmetanorma
public_repos331
account_age_days2,993
评分方式
25/25已发布且可解析 — rubygems 上有 1 个软件包
35/35发布时效 — 最近一次发布于 0 天前
20/20版本历史 — 39 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagessuma
ecosystemsrubygems
any_deprecated
min_days_since_publish0

工程质量

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

70良好 · 占总体的 20%

工程实践

84良好
评分方式
24/24CI 工作流 — 2 个工作流
24/24存在测试
16/16Linter 配置 — .rubocop.yml
0/9.6Pre-commit 钩子
0/6.4.editorconfig
20/20OpenSSF Scorecard:CI-Tests — 8 out of 8 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

安全

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

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

安全态势

46存在风险
评分方式
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
2.5/2.5CI-Tests — 8 out of 8 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
0/7.5Code-Review — Found 0/16 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 5 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
0/2.5许可证 — license file not detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — 无数据
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
5/5SAST — SAST tool is run on all commits
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — 无数据
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate4.6
已排除计分(无数据或不适用):packaging, signed_releases。 其余权重已重新归一化。

AI 就绪度

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

55中等 · 占总体的 0%
评分方式
45/45代理指令 — CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 76 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.76
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes8,037
评分方式
0/18一条命令的引导启动
22/22自动化测试
11/11Lint / 格式化配置 — .rubocop.yml
0/11静态类型检查
0/10可复现环境
0/10已体现的代理实践 — 最近 100 次提交中没有代理编写的提交
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
所用输入
has_nix
has_tests
lockfiles
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
评分方式
0/45可类型检查的代码 — Ruby,未配置类型检查
55/55可控的文件大小 — 采样的 101 个源文件中有 0 个超过 60KB
所用输入
primary_languageRuby
largest_source_bytes11,805
source_files_sampled101
oversized_source_files0

关键数据

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

数据采集警告

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • No resolved dependencies carried a version and a supported ecosystem

更多细节

OpenSSF Scorecard 4.6 / 10
4.6综合

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

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
10CI-Tests8 out of 8 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/16 approved changesets -- score normalized to 0
10Contributorsproject has 5 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
0Licenselicense file not detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
不适用Packagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
10SASTSAST tool is run on all commits
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
直接依赖 10
注册表软件包版本约束清单文件
RubyGemscanonGemfile
RubyGemsmetanormaGemfile
RubyGemsnokogiriGemfile
RubyGemsopenssl~> 3.0Gemfile
RubyGemsrakeGemfile
RubyGemsrspecGemfile
RubyGemsrubocopGemfile
RubyGemsrubocop-performanceGemfile
RubyGemsrubocop-rakeGemfile
RubyGemsrubocop-rspecGemfile
全部依赖 19

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

注册表软件包版本关系
RubyGemscanon直接
RubyGemsmetanorma直接
RubyGemsnokogiri直接
RubyGemsopenssl直接
RubyGemsrake直接
RubyGemsrspec直接
RubyGemsrubocop直接
RubyGemsrubocop-performance直接
RubyGemsrubocop-rake直接
RubyGemsrubocop-rspec直接
RubyGemsexpressir间接
RubyGemsglossarist间接
RubyGemslutaml-model间接
RubyGemsplurimath间接
RubyGemsruby-progressbar间接
RubyGemsrubyzip间接
RubyGemssvg_conform间接
RubyGemstable_tennis间接
RubyGemsthor间接
依赖安全公告 未评估

本报告未能完成公告比对:No resolved dependencies carried a version and a supported ecosystem

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 689,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Ruby": 322720,
        "Shell": 131
      },
      "pushed_at": "2026-07-28T01:06:04Z",
      "created_at": "2024-06-06T08:50:42Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-28T01:06:06Z",
      "description": "Management utility for SUMA (STEP Unified Model-Based Standards Architecture)",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "Ruby",
      "significant_languages": [
        "Ruby"
      ]
    },
    "owner": {
      "blog": "https://www.metanorma.org",
      "name": "Metanorma",
      "type": "Organization",
      "login": "metanorma",
      "company": null,
      "location": null,
      "followers": 95,
      "avatar_url": "https://avatars.githubusercontent.com/u/39362184?v=4",
      "created_at": "2018-05-17T05:14:19Z",
      "is_verified": null,
      "public_repos": 331,
      "account_age_days": 2993
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2025-11-17T03:02:34Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "222b291f5088c8c23031d0f3641f1fbea1b44569",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.5.2",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2026-07-28T01:06:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "147d18185ec3f5bb5a8bd7166e4e005b75bcc38e",
          "body": "…rom output path",
          "is_bot": false,
          "headline": "Fix plain schema export: category level (resources/modules) removed f…",
          "author_name": "KW Kwan",
          "author_login": "kwkwan",
          "committed_at": "2026-07-28T00:35:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a2f13367926dfc96961e2479ef05094adb5ff9c4",
          "body": "…release_command bundle install) (#104)\n\nrequest-checks: true",
          "is_bot": false,
          "headline": "cimas: sync master templates (rubocop todo inherit fix + release.yml …",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-12T11:12:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2637cae55cebef50c213d0ae36d782d0428dcaa9",
          "body": null,
          "is_bot": false,
          "headline": "version bump",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-06T10:36:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "40277af1569b17637ab8ba34b031cf143e462bd5",
          "body": "Rubocop was reporting 552 offenses on main: the cimas-generated .rubocop.yml\ndid not reference .rubocop_todo.yml at all, so the todo was inert. Regenerate\nthe todo (--no-exclude-limit) to grandfather the legacy offenses, and list it\nLAST in inherit_from so it overrides the remote oss-guides config (\n[…]\n manually\"); the next\ncimas-sync will drop this inherit_from ordering and reintroduce the offenses.\nThe durable fix belongs in the cimas rubocop template (emit .rubocop_todo.yml\nlast in inherit_from).",
          "is_bot": false,
          "headline": "chore: regenerate rubocop todo and apply it in inherit_from",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-06T10:34:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6fe4b2f54493bf03147bab04fc0eeba2afb85624",
          "body": "Cimas sync 2026-07-05: propagate #300 gaps + accumulated template drift",
          "is_bot": false,
          "headline": "Merge pull request #102 from metanorma/cimas-sync-2026-07-05",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-06T10:27:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0e618eb3e8e339f6d651aad6d6dac4f572dbaffe",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'main' into cimas-sync-2026-07-05",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-06T06:06:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e14d1f279c814eabff481bcb9c20cfd267681c0c",
          "body": "Memory-bounded staged collection build (opt-in)",
          "is_bot": false,
          "headline": "Merge pull request #103 from metanorma/feature/staged-collection-build",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-06T06:05:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "417e02e3265d7a5c022883c834623e5191df1fd9",
          "body": "…der)",
          "is_bot": false,
          "headline": "style: satisfy rubocop (extract helpers, predicate naming, subject or…",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-06T02:26:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3f551face872b566581d7ef50d3b5903f139adc0",
          "body": "Compile each collection member in its own OS process (preserving cross-document\nreferences as stubs into a content-addressed store), sequentially, then\nreinflate the stored stubs into the final collection. Peak memory is bounded by\na single member instead of the whole collection; the default single-\n[…]\nstaged / staged: true).\n\nNeeds the metanorma#578 engine render options (preserve_unresolved:,\nartifact_store_dir:, reinflate:); Gemfile points metanorma at that feature\nbranch until 2.5.0 is released.",
          "is_bot": false,
          "headline": "feat: opt-in memory-bounded staged collection build (suma#94)",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-06T01:42:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "548e996d2d1b4acd0cd7040c0624f38cfc8a91ea",
          "body": "… 16 from plugin drift)\n\n.rubocop_todo.yml had grown to 368 lines with entries for 525\noffenses, but many entries were stale — Ronald's ongoing refactoring\n(LinkValidator split, NoteProcessor extract, etc.) removed a lot of\nthe offending code without regenerating the todo. Regenerated on\ncurrent mai\n[…]\nttps://github.com/metanorma/suma/pull/102) that failed CI\nwith these offenses should pass on retry.\n\nSurfaced by the 2026-07-05 cimas-sync wave; recorded in the SSOT\nunder the failed-PR sweep section.",
          "is_bot": false,
          "headline": "chore: regenerate .rubocop_todo.yml (drops 193 stale exclusions, adds…",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-05T12:16:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a07c418e6bd48c363eb93f27af9d15b00ff3b0a7",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.5.0",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2026-07-05T01:03:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cafac6ab86238c9f7e5423445e4f06694f31f857",
          "body": "validate_deep_path was ~80 lines with a case statement dispatching\non Expressir node type (Entity → attribute lookup, Type → enum /\nunderlying-type navigation). Adding a new navigable EXPRESS construct\n(functions, procedures) meant editing this method — an OCP violation.\n\nAdd Suma::LinkValidator::St\n[…]\n in REGISTRY — no edits\nto existing Steps or to validate_deep_path.\n\nNew step_spec covers each Step in isolation (no full-pipeline\nscaffolding required). Existing link_validator_spec passes\nunchanged.",
          "is_bot": false,
          "headline": "refactor: split LinkValidator#validate_deep_path into per-type Steps",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-05T00:59:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4557754e366037774b833814050ab8909e515219",
          "body": "EengineConverter's constructor read the XML file:\n\n  def initialize(xml_path, schema_name)\n    @xml_path = xml_path\n    @schema_name = schema_name\n    @xml_content = File.read(xml_path)\n  end\n\nI/O in constructors is a recognised anti-pattern: objects cannot be\ninstantiated without a real file on dis\n[…]\nl_content)\n\nSchemaComparer reads the file and passes content. Updated spec passes\na string and no longer touches the filesystem during construction.\n\nAlso drops the unused @xml_path instance variable.",
          "is_bot": false,
          "headline": "refactor: move File.read out of EengineConverter constructor",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-05T00:59:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4a61e8d68cb61dce82bb1a64c1d6d12511cf3629",
          "body": "TermExtractor carried the entire note-cleaning pipeline as eleven\nprivate methods plus the REDUNDANT_NOTE_REGEX constant. Note\nprocessing is a self-contained concern: turn raw entity.remarks into\na list of clean DetailedDefinition notes for the localized concept.\n\nAdd Suma::NoteProcessor: pure input\n[…]\n → /\\.\\n/.\n\nNoteProcessor has its own spec covering each cleaning rule\n(redundant opening, image refs, double-angle brackets, see-tail\nstripping, definition dedup, list preservation, xref conversion).",
          "is_bot": false,
          "headline": "refactor: extract NoteProcessor from TermExtractor",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-05T00:59:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "66df3c33d0178b56a9cec5cbbda86d8827d2727d",
          "body": "…ster\n\nThe double-Thor pattern (Core delegates to Cli::ExtractTerms.start, which reparses ARGV) was broken because Core has check_unknown_options! enabled via ThorExt::Start. This caused Core to reject any options declared only on the inner Thor class — e.g. --urn, --language-code, --exclude-paths, \n[…]\nice classes (TermExtractor, RegisterManifestGenerator) directly, bypassing the inner Thor wrapper. The inner classes (Cli::ExtractTerms, Cli::GenerateRegister) remain as backwards-compat entry points.",
          "is_bot": false,
          "headline": "fix(cli): declare options on Core for extract-terms and generate-regi…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-05T00:59:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5dacaaf6f1e10dc78300207c0a8ecb78b8348257",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.4.0",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2026-07-05T00:27:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6eb84fd78fc1ee96b645de7d9b7fef227d1ebfef",
          "body": "CodeQL flagged the COMMENT_PATTERN regex /\\(\\*\"(.*?)\\n\\*\\)/m as\npolynomial-time (rb/polynomial-redos). The non-greedy .* with /m is\nvulnerable to catastrophic backtracking on adversarial input starting\nwith (*\" and repeating (*\"a.\n\nReplace the single m-mode regex with a 2-pass String#index scan:\nfind the next COMMENT_START, find the next COMMENT_END after it,\nslice the body. Linear time, no backtracking. Same idempotence and\nwhitespace-normalisation behaviour; existing specs unchanged.",
          "is_bot": false,
          "headline": "fix: clear CodeQL ReDoS alert in ExpressReformatter comment extraction",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-04T23:57:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c9a97cfd7e6e055a2b443cb399842a63c9eb2473",
          "body": "Two coupled changes at the SchemaExporter seam:\n\n(1) Single-parse: SchemaCollection#compile previously built an\nExpressSchema for every schema (stored in @schemas) and then passed\nthe raw manifest entries to SchemaExporter, which constructed a\nsecond ExpressSchema per file and re-parsed. Each schema\n[…]\nIP). Classification\nlives in the CLI adapter, which uses SchemaCategory.for_schema to\nset the right output subdirectory.\n\nUpdated specs use real ExpressSchema instances instead of Structs at\nthe seam.",
          "is_bot": false,
          "headline": "refactor: SchemaExporter accepts loaded ExpressSchema objects",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-04T23:57:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a1e1cdbd973adcc36608a47298aaa2c8d763dec3",
          "body": "Cli::CheckSvgQuality (172 lines) interleaved three concerns: file\ndiscovery (recursive Pathname glob), validation orchestration\n(SvgConform::Validator + per-file Report construction + progress\nreporting), and presentation (filter chain + formatter dispatch).\nNone of the orchestration was reachable f\n[…]\n_report. Both share the scanner.\n\nFormatters (Terminal/Json/Yaml) are unchanged; they were already\ncorrectly seamed. New scanner_spec exercises both scan and scan_file\nagainst real svg_conform output.",
          "is_bot": false,
          "headline": "refactor: extract SvgQuality::Scanner from CLI",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-04T23:57:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1518a72572d4e1046a466c029e32f5386bd18503",
          "body": "Cli::Reformat embedded genuine EXPRESS transformation logic in a\nThor method body: comment-block extraction via regex, whitespace\nnormalisation, no-op detection, and conditional file rewrite. The\ncontent transformation was untestable without Thor and unreachable\nfrom any future programmatic caller.\n\n[…]\novery, read/transform/write. The transformation itself is\ntestable as a pure function.\n\nThe transform is idempotent: reformatting already-reformatted\ncontent returns changed?: false. Verified by spec.",
          "is_bot": false,
          "headline": "refactor: extract ExpressReformatter from CLI",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-04T23:57:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bbe1626758fa0ae14e31bec60022ef15777a6008",
          "body": "Cli::ValidateLinks (169 lines) was a Thor class whose body was the\nimplementation: nine private methods doing file discovery, schema\nloading, link extraction, validation orchestration, and result\nformatting. None of it was reachable from a spec without invoking\nThor.\n\nAdd Suma::LinkValidation: deep \n[…]\n previously had its own copy that had already drifted slightly.\n\nTests use real Expressir parsing on real fixtures; a NullProgress\nadapter lets the service run without the ruby-progressbar dependency.",
          "is_bot": false,
          "headline": "refactor: extract LinkValidation deep module from CLI",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-04T23:57:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ae814e96ec82224b653ce3efabc46c545b21dfb5",
          "body": "TermExtractor classified schemas three different ways in one file:\nsuffix-match on schema.id, filename regex for arm/mim/bom, and a\nstring-based type-switch in generate_entity_definition. Each path\nreimplemented what ExpressSchema::Type and SchemaCategory already own\nas the canonical taxonomy.\n\nAdd \n[…]\nement all disappear.\n\nLocality: adding a new schema type touches one Hash entry, not four\ncode sites. Coverage: :core_model and :standalone schemas no longer\nraise the \"unsupported schema_type\" error.",
          "is_bot": false,
          "headline": "refactor: route TermExtractor through TermClassification",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-04T23:57:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8cb91be8e84b558d28c9e101604ca6935712928a",
          "body": "request-checks: true",
          "is_bot": false,
          "headline": "Cimas sync 2026-07-05: propagate #300 gaps + accumulated template drift",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-07-04T16:36:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1aadf1c63210672e95969f1d0f230ebdfd12ad25",
          "body": "TODO.* directories and TODO*.md files are local planning scratch\nthat must never be committed. Collapses the prior explicit\nper-directory list to a single /TODO* pattern so any future TODO\nscratch path is covered.",
          "is_bot": false,
          "headline": "chore: gitignore /TODO* scratch dirs and files",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-04T01:58:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ce4be8ac002b28901deefe4285cf466350759bc6",
          "body": "The Ruby usage examples referenced the old class-method Processor.run\nAPI and a Suma::SchemaConfig::Config class that does not exist in the\ncodebase. Both are pre-refactor leftovers.\n\n- Processor.run(...) -> Processor.new(...).run\n- Suma::SchemaConfig::Config -> Expressir::SchemaManifest.from_file\n-\n[…]\nSchemaTemplate composition)\n- Document the code-style rules enforced throughout lib/suma/: autoload\n  only, no send / instance_variable_set / respond_to?, Utils.log to\n  $stderr with SUMA_DEBUG gating",
          "is_bot": false,
          "headline": "docs: update README to current API and add architecture section",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-03T03:47:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9230186d40ef1b38c66518663357b39d3e136004",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.3.0",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2026-07-03T03:32:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "05633e491470f846d60e7eb9c333bab5d386d1a1",
          "body": "The previous fix used [^>]+ for the display half, which CodeQL still\nflagged as polynomial because that class can match characters that\nalso appear in the preceding [\\\\w.]+ ref half (overlap creates\nambiguous backtracking).\n\nReplace with [\\\\w. ][\\\\w. ]* — word chars, dots, and spaces only.\nThis is what display text actually contains in practice (entity IDs,\napplication object names, etc.) and excludes the comma/angle-bracket\npunctuation that caused the overlap.",
          "is_bot": false,
          "headline": "fix: tighten express xref display char class to clear CodeQL ReDoS alert",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "393ef24a2d356dcdb005a3737b170739ed80aa11",
          "body": "CodeQL flagged express_reference_to_mention and convert_express_xref\nfor polynomial regular expressions on uncontrolled data (entity\nremarks). Replace ([^,]+) and (.*) captures with tighter character\nclasses that match what EXPRESS identifiers actually contain:\n\n- Reference half: [\\\\w.]+ matches sch\n[…]\np to the closing >> (still\n  permissive enough for free-form display text)\n\nThe new patterns are linear-time and reject pathological inputs that\npreviously could have caused catastrophic backtracking.",
          "is_bot": false,
          "headline": "fix: anchor EXPRESS xref regexes to word chars to avoid ReDoS",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "03b3fc4065db093d0c66ece59c42f5caa446a501",
          "body": "…tion)\n\nIn glossarist 2.8.18+, ManagedConcept#id returns the UUID rather than\nthe human-readable identifier we passed in via id=. The human-readable\nidentifier now lives exclusively on data.id. The UUIDv5 shape check\nremains; the inequality check moves to data.id which is the actual\nschema.entity string we set.",
          "is_bot": false,
          "headline": "test: compare concept.uuid against data.id (glossarist 2.8.18+ conven…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "337b92d176ae0f03eac15bd6982ebc9737ef241c",
          "body": "Add dedicated spec files for every previously-untested class and lock\nin behaviour for the new value objects and services:\n\n- spec/suma/schema_category_spec.rb: SchemaCategory.for_type / for_schema\n  mapping, ALL ordering, member? predicate\n- spec/suma/urn_spec.rb: wildcard stripping, mid-string wil\n[…]\ngister_generator_spec.rb and\nspec/schema_naming_spec.rb (renamed/moved under spec/suma/).\n\nNo doubles; uses real instances, Structs, and Class.new for coercion\ntests. Total examples: 290, all passing.",
          "is_bot": false,
          "headline": "test: comprehensive spec coverage for new and existing classes",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e01b3afc16caafd9e46ae722f5e5d29ac903fa67",
          "body": "- README URN examples now reflect the current ISO 10303-2 SMRL data\n  edition (ed-2). Edition is fully configurable via the --urn CLI option.\n- Document the URN component structure with an ed-3 / French example\n  to make the configurability explicit.\n- CLAUDE.md architecture section updated for the \n[…]\nValidator.\n- Document the code-style rules now enforced codebase-wide: autoload\n  (no require_relative), no send/instance_variable_set/respond_to,\n  Utils.log writes to $stderr with SUMA_DEBUG gating.",
          "is_bot": false,
          "headline": "docs: edition-2 URN examples and updated architecture notes",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "94b6ccda54e092f4259a36246318a87426744414",
          "body": "…erser + SchemaDiscovery\n\nCollectionManifest previously mixed a lutaml-model data model with\nimperative tree-walking logic. Split into three MECE concerns:\n\n- CollectionManifest: pure data model (attributes, YAML mappings,\n  schema_config accessor). No imperative methods.\n- ManifestTraverser: tree-w\n[…]\nbuild_doc_entries, build_added_manifest).\n\nProcessor and SchemaCollection updated to construct a ManifestTraverser\naround the manifest instead of calling imperative methods on the data\nmodel directly.",
          "is_bot": false,
          "headline": "refactor: decompose CollectionManifest into data model + ManifestTrav…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a5747634efb8f3f1913b1bcaeb12fa2ef0d9925",
          "body": "…emaCompiler\n\nSplit the SchemaAttachment/SchemaDocument inheritance hierarchy into\nthree focused components:\n\n- SchemaTemplate::Plain and SchemaTemplate::Document: pure renderers\n  that emit the AsciiDoc body for one schema (no I/O, no schema\n  knowledge). Document adds cross-reference anchors and X\n[…]\nates are\ntestable as pure functions, the compiler is the only class that owns\nfile I/O for adoc/config, and adding a new output flavour means adding\na new template class without touching the compiler.",
          "is_bot": false,
          "headline": "refactor: replace SchemaAttachment/Document with SchemaTemplate + Sch…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dfb892693f9f8ef4f3b1be0c94e291f091f1c662",
          "body": "RegisterManifestGenerator reads an EXPRESS schema manifest and emits a\nGlossarist v3 register.yaml with hierarchical sections:\n\n- Top-level groups per SchemaCategory (Resources, Application Modules,\n  Business Object Models, Core Model, Other)\n- Child sections named via SchemaNaming.prefixed_name (e\n[…]\nges\n\nRenamed from RegisterGenerator to mirror SchemaManifestGenerator and\nthe purpose of the file (producing a register.yaml).\n\nCLI: suma generate-register SCHEMA_YAML OUT_DIR -u URN --id ID --ref REF",
          "is_bot": false,
          "headline": "feat: hierarchical register.yaml generator with URN-aware sections",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c2223d3dff0c44e71b8c493656e4cb38168aab6c",
          "body": "- Consolidate schema-type detection into ExpressSchema::Type.classify\n  (id suffix + path segment); single source of truth used by\n  SchemaExporter, SchemaCategory, RegisterManifestGenerator, TermExtractor\n- Add SchemaCategory value object mapping Type to category identity\n  (id, label, prefix, type\n[…]\nlls that delegate\n- TermExtractor now assigns stable UUIDv5 identifiers and populates\n  ConceptSource#id for cite-key lookups\n- SchemaExporter uses SchemaCategory.for_schema to derive output directory",
          "is_bot": false,
          "headline": "refactor: unify schema classification and extract service objects",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a205b8e811dd14496ec70bf3f5e753b94737debb",
          "body": "- Replace require_relative with Ruby autoload throughout lib/suma/;\n  define parent-namespace autoload files (lib/suma/eengine.rb,\n  lib/suma/cli/core.rb) so children lazy-load\n- Split lib/suma/cli.rb into namespace + Cli::Core dispatcher; delegate\n  subcommands to Cli::Build, Cli::Export, Cli::Comp\n[…]\n(compile, output_directory,\n  schemas_all_path)\n- Utils.log now writes to $stderr by default with SUMA_DEBUG gating\n- Add svg_quality/formatters.rb parent namespace for terminal/json/yaml\n  formatters",
          "is_bot": false,
          "headline": "refactor: autoload CLI namespace and instance-based Processor",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "321a31d1f15a17bee8075525c3991fa63203d69e",
          "body": "- Exclude planning scratch dirs (TODO.clean/, TODO.cleanup/,\n  TODO.refactor/, TODO.remaining/) and vendored *.gem files from git\n- Use rubygems sources for metanorma deps (CI-compatible)\n- Bump glossarist to >= 2.8.7 for Glossarist v3 + UUIDv5 support\n- Regenerate .rubocop_todo.yml via rubocop --auto-gen-config",
          "is_bot": false,
          "headline": "chore: refresh gitignore, dependencies, and rubocop baseline",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0b62773a74c3bdfd810e0f18ec52310b17140178",
          "body": "…r.yaml\n\nRegisterGenerator reads the EXPRESS schema manifest and emits a\nGlossarist v3 register.yaml with hierarchical sections:\n\n  sections:\n    - id: resources\n      names: {eng: Resources}\n      children: [topology_schema, action_schema, ...]\n    - id: modules\n      names: {eng: Application Modul\n[…]\nication (DRY),\n  delegates naming to SchemaNaming (OCP), orders resources before\n  modules.\n- CLI: 'suma generate-register' command added.\n- 30 specs covering naming edge cases and register structure.",
          "is_bot": false,
          "headline": "feat: add RegisterGenerator and SchemaNaming for hierarchical registe…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-07-02T17:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0d71beba0710af12d85dea38e1eb77d3510d29d0",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.2.6",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2026-05-12T03:32:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e2aa442b349ee852921957ceec26b772716f5527",
          "body": "Add explicit permissions blocks to rake.yml and release.yml\nfollowing metanorma/ci best practices.\n\nCloses #88",
          "is_bot": false,
          "headline": "chore: add permissions to CI workflows (Cimas sync)",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-05-12T03:22:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f5063772e0b274b371aea9596d6f978c84e544b0",
          "body": null,
          "is_bot": false,
          "headline": "fix: use GitHub source for metanorma-plugin-lutaml (CI-compatible)",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-05-12T03:02:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d186c854440a41fdccf599f5db8316c35b864dd8",
          "body": "…ubocop",
          "is_bot": false,
          "headline": "fix: update Gemfile for lutaml-model 0.8.x compat, fix specs, clean r…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-05-12T03:02:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b56d564d55787f42a1cef49ec61f670f202df460",
          "body": "…ossarist",
          "is_bot": false,
          "headline": "fix: resolve gemspec duplicate lutaml-model dependency and missing gl…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-05-12T03:02:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b83e9e01764097c4db586928bfdf6168d69cf479",
          "body": "- Add error hierarchy (SchemaNotFoundError, CompilationError, EengineNotAvailableError)\n- Replace all exit/abort calls with proper exception raising\n- Remove all respond_to? and send() calls for proper OOP typing\n- Fix Expressir API references (Expressir::Express::Entity/Type -> Expressir::Model::De\n[…]\n, commented-out blocks across all files\n- Fix schema_exporter fixture paths (relative to manifest file)\n- Add specs for SchemaIndex, SchemaComparer, TermExtractor, Processor (121 examples, 0 failures)",
          "is_bot": false,
          "headline": "refactor: codebase cleanup for lutaml-model 0.8.0 compatibility",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-05-12T03:02:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3e05f3251660e87e29d32bbaea03d82c289b2b47",
          "body": "Add new CLI command to check SVG file quality using svg_conform library.\nSupports batch directory scanning and single file analysis with detailed\nerror breakdown.\n\nFeatures:\n- Batch scanning with progress output and quality report\n- Single file analysis with detailed error grouping by requirement ty\n[…]\nsorting/filtering\n- lib/suma/svg_quality/formatters/*.rb - output formatters\n\nDocumentation:\n- Added check_svg_quality command section to README.adoc\n- Updated suma.gemspec with svg_conform dependency",
          "is_bot": false,
          "headline": "feat: add check_svg_quality command for SVG validation",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-05-12T03:02:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "65aada0c639527b5470b0859fe2f2f2a47e8fd0c",
          "body": null,
          "is_bot": false,
          "headline": "feat: update lutaml-model to 0.8.0",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2026-05-12T03:02:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a3532262f8c7e937a008a6e375d6c040301738b9",
          "body": null,
          "is_bot": false,
          "headline": "update to Relaton 2.0: metanorma/metanorma-standoc#1164",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-04-13T12:37:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "686911659ee15dffaf9deebb5306c086073ef3bb",
          "body": null,
          "is_bot": false,
          "headline": "update to Relaton 2.0: metanorma/metanorma-standoc#1164",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2026-04-13T12:05:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1917e94e2d170ce5165692344a0a93ae764f05a7",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.2.4",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2026-02-04T01:44:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aa8239d25104240a828310823b20cb0a5af162f2",
          "body": null,
          "is_bot": false,
          "headline": "Update gem dependency",
          "author_name": "KW Kwan",
          "author_login": "kwkwan",
          "committed_at": "2026-02-04T01:35:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4bac757ae5474fda088c7e6f583815983fc15603",
          "body": null,
          "is_bot": false,
          "headline": "Fix wrong number of arguments",
          "author_name": "KW Kwan",
          "author_login": "kwkwan",
          "committed_at": "2026-01-30T03:54:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1a07f819220eba18bc3e217213e3e210024e678a",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.2.3",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2026-01-08T03:25:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "19dbd1b89d265e425b6d9a9ce92bc62d25aa0aa1",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-12-18T05:42:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "966093f9a7d9d5a5fe64a23e244e6610054e4d86",
          "body": null,
          "is_bot": false,
          "headline": "chore: fix openssl",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-12-18T05:42:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ba6f97c88f644f7387e8eedc72f117d758203a76",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-12-18T05:42:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d3b14c41de0c87d75908bb7049b70704ab936818",
          "body": null,
          "is_bot": false,
          "headline": "fix: harmonize plain schema output files path, fixes #78",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-12-18T05:42:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b8fb7aaaa8b5693c010d7aaf6688282b2d4974e5",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.2.2",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-12-11T06:17:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fbd043dd9c082e6aad7c52701b6ec04562b3bba7",
          "body": null,
          "is_bot": false,
          "headline": "fix: make expressir commands work",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-12-11T06:10:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "82dd60ab7f234b8be8b544cea093ef5acc4e3fcf",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.2.1",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-12-11T04:04:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a154d21f141daf7eeb799e04ecf7802ade65885e",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-12-11T04:02:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "994d9682898c100e4fcab56e9075b160a7e92eb3",
          "body": "… fixes #75",
          "is_bot": false,
          "headline": "feat: remove `validate ascii` command, moved to lutaml/expressir#278,…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-12-11T04:02:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f09b0f1ba6a3a6cb506b7bbef0787e3c274c0832",
          "body": null,
          "is_bot": false,
          "headline": "gemfile, inane validation error",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2025-11-03T09:44:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "76599c208c97f50c1d177407290358d66af7597c",
          "body": null,
          "is_bot": false,
          "headline": "gemfile",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2025-11-03T09:39:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "06cdfca48c4439fffd6168350c536a4af5abd1f4",
          "body": null,
          "is_bot": false,
          "headline": "version bump",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2025-11-03T09:20:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "01fbfe4bac72d91a779b9d39799165bf1ed6022a",
          "body": "Fix suma dependencies",
          "is_bot": false,
          "headline": "Merge pull request #72 from metanorma/fix-suma-dependencies",
          "author_name": "Nick Nicholas",
          "author_login": "opoudjis",
          "committed_at": "2025-11-03T02:08:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "34b89c5528e81f24e36c1dd013d283f4f83372b7",
          "body": null,
          "is_bot": false,
          "headline": "Fix suma dependencies",
          "author_name": "KW Kwan",
          "author_login": "kwkwan",
          "committed_at": "2025-10-31T07:17:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3034c113c122a9b9aa53d31e202414930bb3c71f",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.1.26",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-10-16T11:13:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5541a219e900519e1ddf4f241acdd539bd1faa95",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-16T11:08:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eb10f0e977ae65d1b3ebedd133c01b4fc23cd804",
          "body": null,
          "is_bot": false,
          "headline": "feat: update to expressir 2.1.29",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-16T11:08:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "499d366e64af5eb1ed193bfaceba3581f0b5edc8",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.1.25",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-10-15T10:04:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "525300b60fbfcbb6198dcab8b5c3c9a1df33cca9",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-15T10:02:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f0f2577e6e12d8e10116c31930c37f463cbc6c5f",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-15T10:02:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a689e4ed9563886fbfd914a4d2db17ff40e42819",
          "body": null,
          "is_bot": false,
          "headline": "feat: suma compare command for EXPRESS schema comparison",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-15T10:02:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "83a8487029837d2b5c214ccf9009097482051352",
          "body": "…, fixes #68",
          "is_bot": false,
          "headline": "fix: fix \"[NameError] uninitialized constant Suma::Cli::Export\" error…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-15T10:02:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3bd5a185197f7f5c6cb493632272a95038df9d7",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.1.24",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-10-12T09:30:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3a6bc4342814d76bc411946414b12b13402410a",
          "body": null,
          "is_bot": false,
          "headline": "fix: duplicated schema type prefixes in paths, fixes #66",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-12T09:28:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d62d3e311ce4e190a79f826ca2030e06a03f8f9b",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-12T08:51:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7b5e743b9765538751a123baf6476b48a5abd487",
          "body": null,
          "is_bot": false,
          "headline": "chore: update rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-12T08:51:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1358de89da183322856b94a7d96f46546085f499",
          "body": "…ded), closes #41",
          "is_bot": false,
          "headline": "chore: add comments for schema manifest creation (no code changes nee…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-12T08:51:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4034a9d9a1875a06ad165d626e74ee016b3bfef2",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-11T10:15:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f5b41664563b619c4ceec81f7dce4d7f6c7fd418",
          "body": "…ble, fixes #33",
          "is_bot": false,
          "headline": "feat: add `suma expressir` subcommand to make coverage feature availa…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-11T10:15:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c9aa438a467188f9ad4bbfb8b6de4b82582b9c3",
          "body": "…ode scanning alert #3",
          "is_bot": false,
          "headline": "fix: ReDoS vulnerability in ExpressSchema#type method, fixes GitHub c…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-09T16:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "066624bdd5b7593ae38cbae3072b6c6b4d368e13",
          "body": "…ode scanning alert #3",
          "is_bot": false,
          "headline": "fix: ReDoS vulnerability in ExpressSchema#type method, fixes GitHub c…",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-09T16:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "29df7e55521e7fac0782e570ae822123950483e4",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-09T16:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4352a64c4591e89c9d890ce3de5082989510ae2e",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-09T16:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "630dc1510d37d59cbc1bfe5b9838149ffeba59c1",
          "body": null,
          "is_bot": false,
          "headline": "chore: rename \"plain EXPRESS\" to \"standalone EXPRESS\"",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-09T16:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "75b512a039e6a48003444c47582fbf5700909a35",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-09T16:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b6896f2d9af854275762e2c05d2be9d09db9a8be",
          "body": null,
          "is_bot": false,
          "headline": "feat: extend export command accept individual EXPRESS files, fixes #61",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-09T16:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "39d7901fd694b2e3fa9bf7ff2c1e3e9f1327dd94",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.1.23",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-10-06T11:39:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4167941975a48d81b996d7dc2c73e1fb9f7bca01",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-06T11:22:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "25af5627c9f9935bfa603ca9f3dc4de3a1e18608",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-06T11:22:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "23f4844e132f0eb77bcc95dbcb5df1c1392b0b13",
          "body": null,
          "is_bot": false,
          "headline": "feat: add export command, fixes #6",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-06T11:22:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e177c5f84c0b064ec091f22f036c01a3a0cdfe6d",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.1.22",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-10-05T02:19:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2a8199ac12a90ea74f8e9aa451b4624c4923f21b",
          "body": null,
          "is_bot": false,
          "headline": "feat: change from terminal-table to table_tennis gem",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-05T02:18:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "589506a1e47e7df2d5a6589e492e928314963ec9",
          "body": null,
          "is_bot": false,
          "headline": "Bump suma to 0.1.21",
          "author_name": "github-actions",
          "author_login": null,
          "committed_at": "2025-10-03T01:20:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a666c5647a82ac34abb197a07ddc981a90ddfb10",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-03T01:18:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35c23dd74fbc9e59e366fbb217d202d8b01a759b",
          "body": null,
          "is_bot": false,
          "headline": "chore: update readme",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-03T01:18:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "131764575850aca1a16f0e89b8f3d3ec0ba18786",
          "body": null,
          "is_bot": false,
          "headline": "chore: update loading order and lutaml xml adapter",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-03T01:18:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "87a2f77d1742444121454a04bb4ce1b9c6d245c0",
          "body": null,
          "is_bot": false,
          "headline": "chore: rubocop",
          "author_name": "Ronald Tse",
          "author_login": "ronaldtse",
          "committed_at": "2025-10-03T01:18:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 1,
      "commits_last_year": 102,
      "latest_release_at": "2025-11-17T03:02:34Z",
      "latest_release_tag": "v0.2.0",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 16,
      "days_since_latest_release": 252,
      "mean_days_between_releases": null
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 75,
      "has_issue_template": false,
      "has_code_of_conduct": true,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": [
        {
          "name": "suma",
          "exists": true,
          "license": "BSD-2-Clause",
          "keywords": [],
          "ecosystem": "rubygems",
          "matches_repo": true,
          "registry_url": "https://rubygems.org/gems/suma",
          "is_deprecated": false,
          "latest_version": "0.5.2",
          "repository_url": "https://github.com/metanorma/suma",
          "versions_count": 39,
          "total_downloads": 29667,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": "2024-06-07T03:53:03.063000Z",
          "latest_published_at": "2026-07-28T01:06:11.087000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 1,
      "watchers": 8,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 13
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 11805,
      "source_files_sampled": 101,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 8037
    },
    "dependencies": {
      "manifests": [
        "Gemfile"
      ],
      "advisories": {
        "error": "No resolved dependencies carried a version and a supported ecosystem",
        "scope": "repository_graph",
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 19,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "rubygems"
      ],
      "dependencies": [
        {
          "name": "canon",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "metanorma",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "nokogiri",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "openssl",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": "~> 3.0"
        },
        {
          "name": "rake",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "rspec",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "rubocop",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "rubocop-performance",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "rubocop-rake",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        },
        {
          "name": "rubocop-rspec",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "canon",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "metanorma",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "nokogiri",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "openssl",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "rake",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "rspec",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "rubocop",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "rubocop-performance",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "rubocop-rake",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "rubocop-rspec",
            "direct": true,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "expressir",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "glossarist",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "lutaml-model",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "plurimath",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "ruby-progressbar",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "rubyzip",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "svg_conform",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "table_tennis",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          },
          {
            "name": "thor",
            "direct": false,
            "version": null,
            "ecosystem": "rubygems"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 19,
        "direct_count": 10,
        "indirect_count": 9
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 3,
        "merged_prs": 54,
        "open_issues": 10,
        "closed_ratio": 0.778,
        "closed_issues": 35,
        "closed_unmerged_prs": 5
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "ronaldtse",
          "commits": 112,
          "avatar_url": "https://avatars.githubusercontent.com/u/11865?v=4"
        },
        {
          "type": "User",
          "login": "kwkwan",
          "commits": 42,
          "avatar_url": "https://avatars.githubusercontent.com/u/29566367?v=4"
        },
        {
          "type": "User",
          "login": "opoudjis",
          "commits": 38,
          "avatar_url": "https://avatars.githubusercontent.com/u/1911039?v=4"
        },
        {
          "type": "User",
          "login": "CAMOBAP",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/2169738?v=4"
        },
        {
          "type": "User",
          "login": "manuelfuenmayor",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/33627611?v=4"
        }
      ],
      "contributors_sampled": 5,
      "top_contributor_share": 0.569
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "rake.yml",
        "release.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [
        ".rubocop.yml"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "8 out of 8 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": 0,
            "reason": "Found 0/16 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 5 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": 0,
            "reason": "license file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 10,
            "reason": "SAST tool is run on all commits",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "222b291f5088c8c23031d0f3641f1fbea1b44569",
        "ran_at": "2026-07-28T01:11:39Z",
        "aggregate_score": 4.6,
        "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-28T01:07:47Z",
      "oldest_open_prs": [
        {
          "number": 35,
          "created_at": "2025-04-04T14:07:42Z",
          "last_comment_at": "2026-07-02T13:45:25Z",
          "last_comment_author": "opoudjis"
        },
        {
          "number": 95,
          "created_at": "2026-07-02T13:44:16Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 108,
          "created_at": "2026-07-25T14:59:30Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ],
      "last_merged_pr_at": "2026-07-28T00:35:16Z",
      "ci_last_conclusion": null,
      "oldest_open_issues": [
        {
          "number": 11,
          "created_at": "2024-09-20T05:52:13Z",
          "last_comment_at": "2024-09-20T14:46:18Z",
          "last_comment_author": "TRThurman"
        },
        {
          "number": 12,
          "created_at": "2024-10-08T11:20:44Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 36,
          "created_at": "2025-04-10T01:49:08Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 37,
          "created_at": "2025-04-10T04:16:37Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 63,
          "created_at": "2025-10-09T12:49:30Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 80,
          "created_at": "2026-01-08T06:12:20Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 85,
          "created_at": "2026-02-10T15:51:58Z",
          "last_comment_at": "2026-07-02T20:22:08Z",
          "last_comment_author": "stuartgalt"
        },
        {
          "number": 90,
          "created_at": "2026-05-26T18:50:29Z",
          "last_comment_at": "2026-06-23T14:19:42Z",
          "last_comment_author": "manuelfuenmayor"
        },
        {
          "number": 94,
          "created_at": "2026-06-30T15:51:13Z",
          "last_comment_at": "2026-07-07T10:31:46Z",
          "last_comment_author": "opoudjis"
        },
        {
          "number": 107,
          "created_at": "2026-07-23T13:10:54Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/metanorma/suma",
    "host": "github.com",
    "name": "suma",
    "owner": "metanorma"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 60,
      "inputs": {
        "security": 46,
        "vitality": 70,
        "community": 40,
        "governance": 66,
        "engineering": 70
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 70,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "commits_last_year": 102,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 16
            },
            "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": "16/52 weeks with commits",
                "points": 11.1,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 16
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "102 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 102
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "moderate",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 62,
            "inputs": {
              "releases_count": 1,
              "latest_release_tag": "v0.2.0",
              "releases_from_tags": false,
              "days_since_latest_release": 252,
              "mean_days_between_releases": null
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "1 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 252 days ago",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 252
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "cadence unknown (single release)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "release_cadence_unknown",
                    "params": {}
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "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": 40,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 5,
            "inputs": {
              "forks": 0,
              "stars": 1,
              "watchers": 8,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "1 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "8 watchers",
                "points": 4.7,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 8
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 67,
            "inputs": {
              "has_readme": true,
              "has_license": false,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": true,
              "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": "no license file detected",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "license_absent",
                    "params": {}
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 13.5,
                "status": "met",
                "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
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 58,
            "inputs": {
              "packages": [
                "suma"
              ],
              "dependents": null,
              "ecosystems": "rubygems",
              "total_downloads": 29667,
              "monthly_downloads": null
            },
            "components": [
              {
                "key": "total_downloads",
                "name": "Total downloads",
                "detail": "29,667 downloads all-time across rubygems",
                "points": 46.5,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_total",
                    "params": {
                      "count": 29667,
                      "ecosystems": "rubygems"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 66,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "at_risk",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 36,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 5,
              "top_contributor_share": 0.569
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 57% of commits",
                "points": 9.7,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 57
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "5 contributors",
                "points": 6.8,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 71,
            "inputs": {
              "merged_prs": 54,
              "open_issues": 10,
              "closed_issues": 35,
              "issue_closed_ratio": 0.778,
              "closed_unmerged_prs": 5
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "78% of issues closed",
                "points": 36.4,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 78
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "54/59 decided PRs merged",
                "points": 35,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 54,
                      "decided": 59
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/16 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 69,
            "inputs": {
              "followers": 95,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "metanorma",
              "public_repos": 331,
              "account_age_days": 2993
            },
            "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": "95 followers of metanorma",
                "points": 14.3,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 95,
                      "login": "metanorma"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "331 public repos, account ~8 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 331
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 8
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "suma"
              ],
              "ecosystems": "rubygems",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on rubygems",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "rubygems"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "39 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 39
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "good",
        "name": "Engineering Quality",
        "value": 70,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 84,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "2 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "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": ".rubocop.yml",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".rubocop.yml"
                    }
                  }
                ],
                "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": "8 out of 8 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": "at_risk",
        "name": "Security",
        "value": 46,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 46,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 4.6
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "8 out of 8 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 0/16 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 5 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 not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is run on all commits",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 3
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 55,
        "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.76,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 8037
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "76 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 76,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 33,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "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": ".rubocop.yml",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".rubocop.yml"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "primary_language": "Ruby",
              "largest_source_bytes": 11805,
              "source_files_sampled": 101,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Ruby without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "Ruby"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/101 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 101,
                      "oversized": 0
                    }
                  }
                ],
                "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": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "No resolved dependencies carried a version and a supported ecosystem"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-28T01:11:55.016478Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/m/metanorma/suma.svg",
  "full_name": "metanorma/suma",
  "license_state": "absent",
  "license_spdx": null
}

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

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

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