公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-24 16:13 UTC

floor / vlist

Accessible, batteries-included ultra efficient virtual list for every framework. Zero deps, 9.7 KB

TypeScriptMIT★ 12 星标⑂ 1 复刻始于 2026年2月在 GitHub 上查看 ↗

floor/vlist 的健康指数为 100 分中的 59 分,处于「中等」区间。 其得分最高的类别是Vitality(83/100),最低的是Security(36/100)。 最近一次更新在 9 天前。 近期的大部分工作由 1 位贡献者完成。

59
总分 / 100
中等

软件健康指数

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

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

评分画像

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

所有权

Floor个人账户
53 关注者30 个公开仓库始于 2010年1月Floor IO

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布标签
npmvlist2.6.11,016479 天前virtual-listvirtual-scrollvirtualized-listinfinite-scrollwindowinglist-virtualizationdom-recyclinglarge-listperformancetypescriptzero-dependencies
npm@floor/vlist⚠ This package has moved to 'vlist'. Install with: npm install vlist1.5.62096899 天前

按类别列示的指标

活力

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

83良好 · 占总体的 22%
评分方式
28.8/36推送新近度 — 最近一次推送于 9 天前
15.2/36提交节奏 — 52 周中有 22 周有提交
18/18提交量 — 最近一年 1,864 次提交
10/10OpenSSF Scorecard:Maintained — 30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
所用输入
commits_last_year1,864
human_commit_share1
days_since_last_push9
active_weeks_last_year22

发布纪律

100优秀
评分方式
27/27有发布版本 — 已发布 34 个发布版本
36/36发布时效 — 最近一次发布版本于 9 天前
27/27发布节奏 — 约每 4.8 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count34
latest_release_tagv2.6.1
releases_from_tags
days_since_latest_release9
mean_days_between_releases4.8
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

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

44存在风险 · 占总体的 18%
评分方式
16.9/60星标 — 12 个星标
0/25复刻 — 1 个复刻
0/15关注者 — 1 位关注者
所用输入
forks1
stars12
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

70良好
评分方式
22.5/22.5README
22.5/22.5许可证 — 可识别的许可证(MIT)
18/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template
评分方式
41.2/80月度下载量 — npm 合计每月 1,225 次下载
0/20注册表被依赖数 — 该生态系统不报告此项
所用输入
packagesvlist, @floor/vlist
dependents
ecosystemsnpm
total_downloads
monthly_downloads1,225
已排除计分(无数据或不适用):注册表被依赖数。 其余权重已重新归一化。

可持续性与治理

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

54中等 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0.8/22.5提交分布 — 头号贡献者编写了 96% 的提交
2.7/13.5贡献者广度 — 2 位贡献者
3/10OpenSSF Scorecard:Contributors — project has 1 contributing companies or organizations -- score normalized to 3
所用输入
bus_factor1
contributors_sampled2
top_contributor_share0.965
评分方式
37.4/46.8议题解决 — 80% 的议题已关闭
37.5/38.3PR 接受 — 已裁定的 PR 中 48/49 已合并
0/15OpenSSF Scorecard:Code-Review — Found 0/6 approved changesets -- score normalized to 0
所用输入
merged_prs48
open_issues11
closed_issues44
issue_closed_ratio0.8
closed_unmerged_prs1
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
12.5/25所有者影响力 — floor 有 53 位关注者
22.9/25既往记录 — 30 个公开仓库,账户约 16 年
所用输入
followers53
owner_typeUser
is_verified
owner_loginfloor
public_repos30
account_age_days6,027
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — npm 上有 2 个软件包
35/35发布时效 — 最近一次发布于 9 天前
20/20版本历史 — 68 个已发布版本
0/20未被弃用 — @floor/vlist: This package has moved to 'vlist'. Install with: npm install vlist
所用输入
packagesvlist, @floor/vlist
ecosystemsnpm
any_deprecated
min_days_since_publish9

工程质量

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

71良好 · 占总体的 20%

工程实践

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

文档

75良好
评分方式
30/30README
0/25文档目录
15/15文档 / 主页站点 — https://vlist.io
10/10仓库描述
10/10主题标签 — 7 个主题标签
10/10Wiki
所用输入
topicslightweight, performance, typescript, virtual-list, virtual-scroll, virtualization, zero-dependencies
has_wiki
homepagehttps://vlist.io
has_readme
has_docs_dir
has_description

安全

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

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

安全态势

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

AI 就绪度

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

64中等 · 占总体的 0%
评分方式
45/45代理指令 — .claude/CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 97 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.97
agent_instruction_files.claude/CLAUDE.md
agent_instruction_max_bytes12,228
评分方式
0/18一条命令的引导启动
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — tsconfig.json
0/10可复现环境
2/10已体现的代理实践 — 最近 100 次提交中有 1 次由代理编写或署名代理
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_configstsconfig.json
agent_commit_share0.01
toolchain_manifests
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — TypeScript(静态类型)
53.1/55可控的文件大小 — 采样的 201 个源文件中有 7 个超过 60KB
所用输入
primary_languageTypeScript
largest_source_bytes80,649
source_files_sampled201
oversized_source_files7

关键数据

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

数据采集警告

  • 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 3.6 / 10
3.6综合

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

10Binary-Artifactsno binaries found in the repo
不适用Branch-Protectioninternal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
10CI-Tests6 out of 6 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/6 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
不适用Packaginginternal error: Client.Actions.ListWorkflowRunsByFileName: internal error: ListWorkflowRunsByFileName: GET https://api.github.com/repos/floor/vlist/actions/workflows/publish.yml/runs?status=success: 502 Server Error []
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities12 existing vulnerabilities detected
直接依赖 1
注册表软件包版本约束清单文件
npmvlist^1.5.5shim/package.json
全部依赖 7

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

注册表软件包版本关系
npmvlist^1.5.5直接
npm@happy-dom/global-registrator^20.9.0间接
npm@types/bun^1.0.0间接
npm@types/jsdom^27.0.0间接
npmhappy-dom^20.9.0间接
npmjsdom^28.0.0间接
npmtypescript^5.0.0间接
依赖安全公告 未评估

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [
        "lightweight",
        "performance",
        "typescript",
        "virtual-list",
        "virtual-scroll",
        "virtualization",
        "zero-dependencies"
      ],
      "is_fork": false,
      "size_kb": 3906,
      "has_wiki": true,
      "homepage": "https://vlist.io",
      "languages": {
        "CSS": 56059,
        "JavaScript": 56,
        "TypeScript": 3091655
      },
      "pushed_at": "2026-07-15T05:45:55Z",
      "created_at": "2026-02-01T18:09:39Z",
      "owner_type": "User",
      "updated_at": "2026-07-23T03:37:11Z",
      "description": "Accessible, batteries-included ultra efficient virtual list for every framework. Zero deps, 9.7 KB",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript"
      ]
    },
    "owner": {
      "blog": "https://floor.io",
      "name": "Floor",
      "type": "User",
      "login": "floor",
      "company": "Floor IO",
      "location": "Switzerland",
      "followers": 53,
      "avatar_url": "https://avatars.githubusercontent.com/u/187733?v=4",
      "created_at": "2010-01-22T15:09:44Z",
      "is_verified": null,
      "public_repos": 30,
      "account_age_days": 6027
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v2.6.1",
          "kind": "patch",
          "published_at": "2026-07-15T05:46:50Z"
        },
        {
          "tag": "v2.6.0",
          "kind": "minor",
          "published_at": "2026-07-08T02:55:03Z"
        },
        {
          "tag": "v2.5.1",
          "kind": "patch",
          "published_at": "2026-06-13T10:48:29Z"
        },
        {
          "tag": "v2.5.0",
          "kind": "minor",
          "published_at": "2026-06-09T09:41:57Z"
        },
        {
          "tag": "v2.4.2",
          "kind": "patch",
          "published_at": "2026-06-09T06:02:35Z"
        },
        {
          "tag": "v2.4.1",
          "kind": "patch",
          "published_at": "2026-06-07T19:52:14Z"
        },
        {
          "tag": "v2.4.0",
          "kind": "minor",
          "published_at": "2026-06-07T18:29:39Z"
        },
        {
          "tag": "v2.3.0",
          "kind": "minor",
          "published_at": "2026-06-05T14:40:26Z"
        },
        {
          "tag": "v2.2.0",
          "kind": "minor",
          "published_at": "2026-06-02T11:04:02Z"
        },
        {
          "tag": "v2.1.2",
          "kind": "patch",
          "published_at": "2026-06-01T23:28:56Z"
        },
        {
          "tag": "v2.1.1",
          "kind": "patch",
          "published_at": "2026-06-01T14:08:32Z"
        },
        {
          "tag": "v2.1.0",
          "kind": "minor",
          "published_at": "2026-05-30T11:15:13Z"
        },
        {
          "tag": "v2.0.5",
          "kind": "patch",
          "published_at": "2026-05-29T16:31:01Z"
        },
        {
          "tag": "v2.0.4",
          "kind": "patch",
          "published_at": "2026-05-28T15:30:37Z"
        },
        {
          "tag": "v2.0.3",
          "kind": "patch",
          "published_at": "2026-05-28T09:27:58Z"
        },
        {
          "tag": "v2.0.2",
          "kind": "patch",
          "published_at": "2026-05-28T07:48:58Z"
        },
        {
          "tag": "v2.0.1",
          "kind": "patch",
          "published_at": "2026-05-27T10:06:58Z"
        },
        {
          "tag": "v2.0.0",
          "kind": "major",
          "published_at": "2026-05-27T09:41:57Z"
        },
        {
          "tag": "v1.9.1",
          "kind": "patch",
          "published_at": "2026-05-21T11:14:17Z"
        },
        {
          "tag": "v1.9.0",
          "kind": "minor",
          "published_at": "2026-05-17T19:13:11Z"
        },
        {
          "tag": "v1.8.3",
          "kind": "patch",
          "published_at": "2026-05-13T22:48:48Z"
        },
        {
          "tag": "v1.8.2",
          "kind": "patch",
          "published_at": "2026-05-13T12:34:14Z"
        },
        {
          "tag": "v1.8.1",
          "kind": "patch",
          "published_at": "2026-05-13T09:33:37Z"
        },
        {
          "tag": "v1.8.0",
          "kind": "minor",
          "published_at": "2026-05-13T06:30:00Z"
        },
        {
          "tag": "v1.7.9",
          "kind": "patch",
          "published_at": "2026-05-13T06:02:50Z"
        },
        {
          "tag": "v1.7.8",
          "kind": "patch",
          "published_at": "2026-05-12T20:16:50Z"
        },
        {
          "tag": "v1.7.7",
          "kind": "patch",
          "published_at": "2026-05-11T08:21:15Z"
        },
        {
          "tag": "v1.7.6",
          "kind": "patch",
          "published_at": "2026-05-10T14:44:29Z"
        },
        {
          "tag": "v1.7.5",
          "kind": "patch",
          "published_at": "2026-05-08T07:08:58Z"
        },
        {
          "tag": "v1.7.4",
          "kind": "patch",
          "published_at": "2026-05-02T13:41:55Z"
        },
        {
          "tag": "v1.7.3",
          "kind": "patch",
          "published_at": "2026-05-01T07:36:39Z"
        },
        {
          "tag": "v1.7.2",
          "kind": "patch",
          "published_at": "2026-05-01T00:22:53Z"
        },
        {
          "tag": "v1.7.1",
          "kind": "patch",
          "published_at": "2026-04-30T10:14:56Z"
        },
        {
          "tag": "v1.7.0",
          "kind": "minor",
          "published_at": "2026-04-29T10:05:15Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "7c39284b964a4d4e7b67821d17a622cf599eaed8",
          "body": "chore(release): v2.6.1",
          "is_bot": false,
          "headline": "Merge pull request #121 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-07-15T05:45:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c6c29caeb6aa5897545574de541bfdbac783a920",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v2.6.1",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-15T05:44:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e22e42dd074b3b570f26f2b7dfc15d2b5f5908cc",
          "body": "CHANGELOG [2.6.1] entry + README/npm-readme version summary. Base size\nunchanged (9.7 KB gzipped); no size-table impact.",
          "is_bot": false,
          "headline": "docs: prepare v2.6.1 release notes (#60)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-15T05:16:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b6c1cf18d339e5b29b9e0a581967c2336d8dfb28",
          "body": "Grid PageUp/PageDown column preservation (#60).",
          "is_bot": false,
          "headline": "Merge branch 'fix/60-grid-page-nav' into staging",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-15T05:08:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dd09a86d96cb2c022b88cf3e365bdd5a887eacd1",
          "body": "In grid mode, PageUp from an item in the first row (and PageDown from the last\nrow) clamped the target to the absolute first/last item, snapping focus to the\ncorner — i.e. Home/End behaviour — instead of staying in the same column.\n\nAdd a shared `clampPageTarget` helper that, in grid mode (`columns \n[…]\no both the selection and a11y keyboard handlers\n(including the layout↔data-index path). Linear lists (`columns <= 1`) keep the\nplain `[0, total-1]` clamp.\n\nAdds test/utils/grid-nav.test.ts (10 cases).",
          "is_bot": false,
          "headline": "fix(a11y): PageUp/PageDown preserve column at grid boundaries (#60)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-09T16:33:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1d1a469e2d8f191e77dbdc0dd13563f871959abe",
          "body": "chore(release): v2.6.0",
          "is_bot": false,
          "headline": "Merge pull request #120 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-07-08T02:53:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b1142f80fcbf3c8c440b09c7bd8c9459e008f803",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v2.6.0",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-08T02:48:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef7b3998ed44601ee864429280acbfda19556043",
          "body": "Add CHANGELOG [2.6.0] entry and update the version summary in README.md and\nnpm-readme.md. Plugin size table verified against `bun run size` (unchanged;\nbase stays 9.7 KB gzipped).",
          "is_bot": false,
          "headline": "docs: prepare v2.6.0 release notes (changelog + readme)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-08T02:43:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "72f593c72ffe266c403402f66e60674893458b7d",
          "body": "Shared vlist/config resolver for framework adapters (fixes #119).",
          "is_bot": false,
          "headline": "Merge branch 'fix/119-adapter-config-resolver' into staging",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-08T02:42:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "203ebfcff8d21acb602af297158c2f9a2d3a260b",
          "body": "Introduce a `vlist/config` subpath export owning the high-level `VListConfig`\ntype and the config→plugins translation (`resolvePlugins`,\n`createVListFromConfig`), previously duplicated across the four framework\nadapter repos.\n\nRoot-cause fix for #119: `CreateVListConfig` re-declared inline `item`/`s\n[…]\nse bundle stays 9.7 KB gzipped (tree-shaking\nintact). Adds test/config/resolve.test.ts (25 tests incl. #119 + native\nscrollbar regressions).\n\nFixes #119\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(config): add shared vlist/config resolver for framework adapters",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-07-08T02:41:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "02f859ab822bb4339c30e14aa3812616275d5d10",
          "body": "Release v2.5.1",
          "is_bot": false,
          "headline": "Merge pull request #118 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-06-13T10:47:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9d4ae6accd45f5511b3a9525094333aad487944f",
          "body": "Carousel snap refinements + fixes (groups bounded scroll, carousel snapEasing,\nstatic-variant reposition, async idle reconcile, grouped-table data indices).\nCorrect carousel size in both READMEs (+3.4 KB; npm-readme was stale at +2.3).",
          "is_bot": false,
          "headline": "chore(release): v2.5.1",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-13T10:42:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e2ba4b04e7e80009d60295b2206b3a51edabca40",
          "body": "The groups plugin was the one layout plugin never migrated to the bounded\nscroll model, so enabling scroll: { mode: 'bounded' } broke grouped lists:\n\n1. buildTransform positioned items at their raw absolute offset instead of\n   offset - baseOffset, rendering them millions of px off-screen (blank lis\n[…]\nll three are no-ops in native mode (baseOffset is 0). Adds groups-bounded\nintegration tests (list deep-scroll, list gradual-scroll no-overlap, grid\ndeep-scroll), each verified to fail without its fix.",
          "is_bot": false,
          "headline": "fix(groups): make the groups plugin bounded-scroll aware (RFC-012)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-13T07:22:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8934709b2c5f2c983da42d4003eebdd67c4a5cc4",
          "body": "…ument\n\nThe call passed (target, duration, undefined, snapEasing), parking snapEasing\nin the onComplete slot of the current\nsmoothScrollTo(target, duration, easing?, onComplete?) signature. A configured\nsnapEasing was silently ignored (snaps used the default easing) and it tripped\nthe type checker. Pass it as the easing argument.",
          "is_bot": false,
          "headline": "fix(carousel): forward snapEasing to smoothScrollTo as the easing arg…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-12T23:52:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bc093e218cd3aa8413d63ae10c3030b24543ad26",
          "body": "…ange\n\nloadPendingRange bailed out when pendingRange was null. During a momentum\nscroll the final onAfterScroll can land in the slow path, which calls\nresetDeceleration() (clearing pendingRange) without re-ensuring the settled\nchunk — so onIdle loaded nothing and the viewport stayed on placeholders.\n\nAlways ensure the currently-visible range on idle. ensure() dedupes against\nloaded/in-flight chunks, so it is a no-op when the range is already loaded.",
          "is_bot": false,
          "headline": "fix(data): reconcile the visible range on idle regardless of pendingR…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-12T23:52:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a9b1668bb2df80edf604abc0d05dc5f190c847cb",
          "body": "In grouped table mode the engine runs in layout-index space (header\npseudo-rows interleaved with data rows), but the table render published raw\nlayout indices as engineState.startIndex/visibleCount. The async data plugin\nreads those as data indices, so it requested a range shifted by the header\ncoun\n[…]\nrender's entry.dataIndex fill); plain tables keep\nthe 1:1 path. Resolve the lookup once, and drop the per-row visible* array\nwrites that only the default render pipeline reads (the table replaces it).",
          "is_bot": false,
          "headline": "fix(table): publish data indices to the loader in grouped tables",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-12T23:52:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f69186d8bd17a5af8905aa2768980ebcfb2ce162",
          "body": "…ap for full variant\n\n- Add `snapDirection` option (default true) — snaps in the user's scroll\n  direction instead of always to nearest item\n- Add `snapEasing` option — custom easing function for snap animation\n- Force snap on for `full` variant regardless of `snap: false`\n- Capture last scroll dire\n[…]\ne resets it to 0\n\nAlso:\n- Simplify rebuild utility — pass snapshot directly via `restore` instead\n  of sessionStorage round-trip\n- Fix snapshots plugin — `restore` now takes precedence over `autoSave`",
          "is_bot": false,
          "headline": "feat(carousel): direction-aware snap, configurable easing, enforce sn…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T17:35:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3a6a4ec38ab649c7b1001187170a117289e5a489",
          "body": "fix(carousel): static variant smooth scroll + concurrent test fixes",
          "is_bot": false,
          "headline": "Merge pull request #112 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-06-09T10:32:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dd446ffe9158e2b61a645b9d22e5881916a27375",
          "body": "Use local container/list variables with try/finally cleanup in async tests\nthat previously shared file-level state, preventing races under\nbun test --concurrent. Resize test additionally flushes the ResizeObserver\ninstall synchronously to avoid leaking the global mock across yields.",
          "is_bot": false,
          "headline": "fix(test): isolate shared state for concurrent test stability",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T10:30:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "76218fb20cb17fc9b6f6e3cd3fd50de88dea4b58",
          "body": "… scroll\n\nThe updateItemLayout() early return guard prevented DOM transform updates\nfor static carousels (no layout engine). Relax the guard to only bail when\nrealTotal <= 1, so the else branch computes absOffset - baseOffset each\nframe during smooth scroll animations.",
          "is_bot": false,
          "headline": "fix(carousel): allow static variant to reposition items during smooth…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T10:30:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f9b59acc3b479a4ee5d18770025eadb0a0ccffed",
          "body": "v2.5.0 — Carousel stylesheet, selectAll async fix",
          "is_bot": false,
          "headline": "Merge pull request #111 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-06-09T09:39:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4b596b43bea538f6dfa26fbd4d2c52a772d02f7f",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v2.5.0",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T09:36:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "79c2eba7b8955f75ebd1575ebb1af08c72a84407",
          "body": "…l-focal-width\n\nLibrary-shipped structural styles for carousel slides: media stabilization\n(no image breathing during transitions), overlay visibility driven by\nrole-weight, and text truncation. Focal-width CSS variable locks media to\nthe focal slot size with centered absolute positioning for parallax pan.",
          "is_bot": false,
          "headline": "feat(carousel): add vlist-carousel.css stylesheet and --vlist-carouse…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T09:08:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f35cff2915fe97ff9d596f6ffe6e3e6055377daa",
          "body": "… unloaded\n\ndoSelectAll/doSelectRange now add placeholder IDs for items not yet fetched\nby the data plugin. The existing claimPlaceholderSelection mechanism swaps\nthem for real IDs when data loads. Also resolves loadedItemFn before the\nselectAll loop, marks placeholder DOM elements as selected in itemStateFn,\nand guards _seedSelection against restoring multi-selection into single mode.",
          "is_bot": false,
          "headline": "fix(selection): selectAll with async data selects all items including…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T09:08:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f4392732f58b5a74973f9f8eac3cf79bc3409f34",
          "body": "Maps role-weight to the item's rendered size relative to the focal\nslot — text fades out as items shrink at the edges and fades in as\nthey grow.",
          "is_bot": false,
          "headline": "feat(carousel): add \"size\" textFade mode, use it for uncontained",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T07:39:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2e9dca856d52035c6235792e37a40c0becde4171",
          "body": "…ewport offset\n\nroundedOffset is relative to native scrollTop=0, not the visible viewport.\nSubtracting the native scroll position gives correct viewport-relative\ncoordinates for the visibility ratio.",
          "is_bot": false,
          "headline": "fix(carousel): viewport role-weight used content offset instead of vi…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T07:28:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b3352c0ba2785629a6bd87f7375554177e4267c3",
          "body": "Add textFade (\"role\" | \"viewport\") to SlotConfig and new NoEngineConfig\ntype for presets without a layout engine. PresetResult union lets any\nresolver control overlay behavior. --vlist-carousel-role-weight variable\ndrives text overlay visibility per-frame: \"role\" mode fades by slot\nprogress, \"viewport\" mode fades by container-edge visibility.",
          "is_bot": false,
          "headline": "feat(carousel): textFade preset option and role-weight CSS variable",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T07:18:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8f23fbc6f82db70a7d71b43a9a043b00903f5043",
          "body": "v2.4.2",
          "is_bot": false,
          "headline": "Merge pull request #110 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-06-09T06:01:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a574c707fc3cbd4da64448b0061e8c85405c93cb",
          "body": "…ncItemCount",
          "is_bot": false,
          "headline": "test(carousel): cover SlotConfig object variant and variable-width sy…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T05:49:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3efa1a1f4ce3f3446ae60ace9bbab46d271f2a89",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v2.4.2",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T05:47:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "79620a5dcb425bdb0260286f51fa1827792bac3b",
          "body": "Replace hardcoded switch in resolvePreset with a Map-based registry.\nPresets are SlotConfigResolver functions registered by name — users\ncan add or override presets via registerPreset(). The variant config\nnow accepts a string, SlotConfig, or SlotConfigResolver function.",
          "is_bot": false,
          "headline": "feat(carousel): modular preset registry",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T05:24:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1adbe6ad1b7a173cb9e2883d95b41095ac188555",
          "body": "MD3's \"Uncontained multi-aspect ratio\" variant positions the focal item\nat the left viewport edge with neighbors peeking from the right — not\ncentered. Remove centerShift from the no-layout-engine path.",
          "is_bot": false,
          "headline": "fix(carousel): left-align multi-aspect items per MD3 uncontained spec",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T04:20:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c8964a83698b91227531ee8c80ce75e0afb50a84",
          "body": "The no-layout-engine path (used by multi-aspect variant) positioned items\nfrom the left edge, making the focal item appear off-center. Compute\ncenterShift from the interpolated focal item size and apply it to all\nitem offsets so the active item stays centered in the viewport.",
          "is_bot": false,
          "headline": "feat(carousel): focal centering for multi-aspect variable-width items",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T04:17:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "50fa46f6ad2b4943cb5aa5db7dd26f2f8644019b",
          "body": "…iant\n\nReplace scalar stepSize with stepSizes[] array and stepOffsets[] prefix\nsums. Binary search for variable widths, fast division for uniform —\none pipeline handles both. Adds multi-aspect variant that renders items\nat their natural widths without a slot engine.",
          "is_bot": false,
          "headline": "feat(carousel): support per-item variable widths for multi-aspect var…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T03:03:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "426081247a87eff338b5ea9d30aa8712845e481e",
          "body": "…cal boundary\n\nItems shrinking to 0 at the focal-boundary flip kept a full gap until\nthe instant they disappeared, injecting a gap-sized jump into cumulative\noffsets. Fade the gap proportionally with the item size so the offset\nstays continuous through the flip.",
          "is_bot": false,
          "headline": "fix(carousel): fade gap with item size to eliminate offset jump at fo…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-09T03:03:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b745e91ad7fedb7eb280a05f6fcb6a7a21c45528",
          "body": "v2.4.1",
          "is_bot": false,
          "headline": "Merge pull request #109 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-06-07T19:51:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e182f3ac9ef27621ff8c42db29ec43128f740567",
          "body": "The custom scrollbar's max position was computed from engineState.totalSize\nalone, which excludes padding. This made the thumb stop short by\nmainAxisPadding pixels when dragged to the bottom — the End key and\nscrollToIndex worked because they route through the bounded handler's\nsetLogical which uses\n[…]\ned to updateBounds, and route\nthe scroll callback through ctx.scrollTo (which reaches setLogical\ndirectly) instead of ctx.scroll.setPixelEquivalent (which clamps via the\nadapter's sizeCache-only max).",
          "is_bot": false,
          "headline": "fix(scrollbar): include main-axis padding in max scroll bounds",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T19:49:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5bbd1a26986337a6896f80a5c85bb252c1c0fcc5",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v2.4.1",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T19:35:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "866031085734c2feef3cb9c125c8b87e4754f399",
          "body": "… nav\n\nThe keyboard handler skipped scrollFocusIntoView when nav.navigate was\nset, assuming the custom navigate handles scrolling. Masonry provides\nnavigate for lane-aware 2D movement but relies on _scrollItemIntoView\nfor scrolling. Now scrollFocusIntoView runs when sivFn is registered\n(masonry) or when there is no custom navigate (grid/standard lists).",
          "is_bot": false,
          "headline": "fix(selection): scroll focused item into view during masonry keyboard…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T19:32:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fa2c512fcfb6e741edfe6c063d3ccc315f2457ac",
          "body": "The bounded scroll handler ignored deltaX-dominant wheel events for\nhorizontal lists, falling through to native scroll. Native scroll is\nlimited by the bounded runway (~900px), causing missing items during\nfast macOS trackpad two-finger swipes. In wrap mode (carousel), these\nevents are now intercepted and processed synthetically like deltaY.",
          "is_bot": false,
          "headline": "fix(core): intercept trackpad horizontal swipe in carousel wrap mode",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T19:21:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9240c53de869b6dd7b6f06742863eacc96345884",
          "body": "Track the intended virtual index target so rapid button clicks chain\ncorrectly instead of computing from the mid-animation scroll position.\nClear the target on idle so manual scroll/drag still works.",
          "is_bot": false,
          "headline": "fix(carousel): rapid next/prev clicks no longer skip or stutter",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:56:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7b4f77c8cd635f5c1e64d976ceefe7e83f587e6",
          "body": "v2.4.0 — Bounded logical scroll model (RFC-012)",
          "is_bot": false,
          "headline": "Merge pull request #107 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-06-07T18:28:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2c0ca81fe4fd602c837e9f793020e40e8818fcbe",
          "body": null,
          "is_bot": false,
          "headline": "docs: mention carousel plugin in 2.4.0 tagline, sync npm-readme sizes",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:26:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "77c99a24a9ac5392fdc16d72745baeb065136822",
          "body": "…cItemCount",
          "is_bot": false,
          "headline": "test(carousel): cover presets, keyboard handler, snap, navConfig, syn…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:25:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c6b2eee6a828b593d8ec9b66e109be6c036aa3b",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): fix base size claim in 2.4.0 entry",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:14:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3e371c4d78d0beb3ce112a04f921042204d51c81",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v2.4.0",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:12:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ff6755d9bc9de36e18b6f560d04f03092c23801",
          "body": null,
          "is_bot": false,
          "headline": "Merge logical-scroll-model (RFC-012 + Phase A)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:09:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "441698c0f42dfc70857f999be18b1cf903f5a2ab",
          "body": "RFC-013 Phase A: grid/table/masonry route through bounded scroll.\nScale deprecation stub. File renames (runway.ts, adapter.ts).",
          "is_bot": false,
          "headline": "Merge rfc-013-renderer-routing into logical-scroll-model",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:07:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "122a4f8b83c3b220c4a8eb10e2ebbf6e7d808792",
          "body": "scale() returns a no-op plugin with a one-time console.warn pointing\nusers to scroll: { mode: \"bounded\" }. Preserves the import so existing\ncode doesn't break on a minor bump. Removed entirely in 3.0.",
          "is_bot": false,
          "headline": "feat(scale): deprecation stub for 2.4.0 → 3.0 migration",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:06:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ed5c28ed3362b8af0ceec5f3486f224f401538a4",
          "body": "One-word filenames to match the directory convention (scroll, state,\nsizes, pool, etc.). Coverage tests for runway.ts added: 67.8% → 99.4%\nline coverage — wheel handler, idle detection, smooth scroll, cancel.",
          "is_bot": false,
          "headline": "refactor(core): rename bounded-scroll → runway, scroll-model → adapter",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:06:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "802f7a172a9cd9e8d206f87044e68621dfe925a9",
          "body": null,
          "is_bot": false,
          "headline": "chore: add .agents/ and .env.agents to gitignore",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T18:05:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "54fb8f0e1732d111d398883eee50358c214b52cc",
          "body": "These renderers install setRenderFn, so core skips syncContentSize and they\nown content sizing. They wrote the full physical size and absolute transforms,\nreintroducing the browser ~16.7M px element limit in bounded mode.\n\n- subtract engineState.baseOffset from item transforms (no-op in native mode)\n[…]\nontentSize so the bounded handler\n  caps it to the runway, guarded by lastContentTotalSize\n- masonry re-syncs content size on the first render since the bounded handler\n  is created after plugin setup",
          "is_bot": false,
          "headline": "fix(render): route grid/table/masonry through bounded scroll (RFC-013)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T17:17:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "283b2d5d42725cec361a9574ae61fa7c89bb5f36",
          "body": "Two RFC-012 review fixes:\n\n- The ResizeObserver updated containerSize and re-rendered but never called\n  boundedHandler.refresh(), so the runway and max-logical bounds stayed sized\n  to the old viewport. Refresh the handler before rendering on resize.\n\n- page() installs window-based scroll fns; the \n[…]\nt handler, silently breaking both. Throw an\n  explicit error when page() is combined with scroll: { mode: \"bounded\" } or\n  the carousel plugin (bounded wrap). Bounded page-mode is not implemented yet.",
          "is_bot": false,
          "headline": "fix(core): refresh bounded runway on resize; guard page() + bounded",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T16:08:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d67ff7282e8cebc73584f07878946e3361e381e3",
          "body": "… Phase 4)\n\nThe carousel previously managed its own silent rebasing, smooth-scroll\nanimation, and raw scrollTop writes over a content element sized to the\nfull virtual window. That duplicated the bounded handler's job and assumed\nscrollTop == logical position.\n\nIt now requests a wrap-capable bounded\n[…]\n value.\n\nThe mock PluginContext scroll writes now mutate scrollPosition to match the\nreal adapter; this corrected an autosize test that was asserting a mock\nartifact (anchor compensation accumulates).",
          "is_bot": false,
          "headline": "refactor(carousel): route infinite loop through bounded wrap (RFC-012…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T15:59:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2f212b1053c3463c46ace18cefc071440507d2c1",
          "body": "Remove the legacy rendering/compression domain that src/core/ already\nsuperseded. These modules were reachable only via vlist/internals, never on\nthe runtime path, so the main bundle is unaffected (base stays 9.4 KB).\n\n- delete src/rendering/{renderer,viewport,scale,scroll,measured}.ts and\n  src/plu\n[…]\nomments\n- delete the dead compression tests; de-compress the grid/table renderer\n  tests; update the size-overflow assertion\n\nbun run typecheck clean, bun test 3326 pass / 0 fail, bun run build green.",
          "is_bot": false,
          "headline": "refactor(core): delete dead compression internals (RFC-012 Phase 3b)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T15:17:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7b4d282bf639d118dcec545ba8ede37ffa369430",
          "body": "Base 8.1 → 9.4 KB (bounded scroll now in core), drop the scale() row,\nrefresh every plugin delta against `bun run size`, add carousel(), and\npurge stale scale references. Remove scale from scripts/size.ts.",
          "is_bot": false,
          "headline": "docs: update bundle sizes after scale plugin removal",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T15:03:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5a90a36aedfc2edd50452d0ffb2be73ec8e4d118",
          "body": "Bounded logical scroll supersedes scroll compression. Remove the scale\nplugin, its public export and build entry, and the now-dead compression\nbranches across core (state, wheel handler) and the scrollbar, snapshots,\ngroups, grid, table, and tree plugins.\n\nLegacy src/rendering/* and internals compression references are left for\na follow-up pass; they are not on the live engine path.",
          "is_bot": false,
          "headline": "refactor(core): remove scale plugin and compression path (RFC-012)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T13:58:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "78f7e3edfbd32142bd431ca228b8902c049a076a",
          "body": "Add an opt-in `scroll: { mode: \"bounded\" }` model that sizes the content\nelement to a viewport-multiple runway instead of the full virtual size,\navoiding the browser's ~16.7M px element limit without the scale plugin's\ncompression. The public scroll position is an absolute logical pixel;\nnative scro\n[…]\n autosize derives end-detection from the size cache, not scrollHeight.\n- Runway defaults to 2x viewport (configurable via scroll.runway,\n  clamped up to a 1.5x floor for native scroll/touch momentum).",
          "is_bot": false,
          "headline": "feat(core): bounded logical scroll model (RFC-012)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-07T01:50:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f2d475fa86ea40c613c8a15019d3c8ac0b683e16",
          "body": "Carousel plugin (RFC-011): infinite-loop scrolling with configurable\nlayout engine. 70 tests, +2.2 KB gzipped.\n\n- Layout engine (engine.ts) with slot-based model\n- Presets: full, hero, hero-center, multi, uncontained, static\n- Dynamic item sizing on every scroll frame\n- Built-in keyboard navigation \n[…]\non sync (preserves logical index on item changes)\n- Smooth animation layout sync (forceRender on completion)\n- carousel:change event, CSS variables per element\n- 3815 total tests pass, typecheck clean",
          "is_bot": false,
          "headline": "Merge feat/carousel-plugin into staging",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T19:33:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "10bbe680449536d45fab9324450a11b6a3d2f8fc",
          "body": "Truly circular: rebaseIfNeeded() now runs on every onAfterScroll frame,\nnot just when snapEnabled is true. Without this, free scroll (no snap)\nwould hit the edge of the 101-cycle virtual window and stop.",
          "is_bot": false,
          "headline": "fix(carousel): rebase fires on every scroll, not just when snap enabled",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T19:32:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "759ae7efb70df0dff04e5c86dc01499c66ae5eb1",
          "body": "…malization\n\n8 new tests (62 → 70):\n- Keyboard: registers keydown handler, sets tabindex=0\n- carousel:change: emitted by next() with correct logical index,\n  prev() wraps correctly\n- Index mapping: _layoutToDataIndex maps virtual→logical via modulo\n- Mutation sync: getItems().length reflects additions\n- Normalized scroll: getCarouselState().scrollPosition within one lap",
          "is_bot": false,
          "headline": "test(carousel): keyboard, events, index mapping, mutation, scroll nor…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T18:37:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0323dedb09f4a80bb3137bfeada2699cd71742f7",
          "body": "Keyboard navigation:\n- Carousel registers keydown handler via ctx.registerKeydownHandler\n- Sets tabindex=0 on content element for focusability\n- Arrow keys use next()/prev() with smooth scrolling (same as buttons)\n- Home/End use goTo() with smooth scrolling\n- setNavConfig({ navigate, total }) for se\n[…]\nMutation sync:\n- syncItemCount rebases scroll to preserve logical index\n- Scroll setter updates engineState immediately\n- next()/prev() emit carousel:change directly\n\n3815 tests pass, typecheck clean.",
          "is_bot": false,
          "headline": "fix(carousel): built-in keyboard nav, smooth animation layout sync",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T18:32:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e9da69e0ae889a103e1ce3ed78fc7ca18817f054",
          "body": "P1 fix from cadex review: virtual scroll indices (e.g. 247 for a 5-item\nlist) leaked into data-index, aria-posinset, aria-setsize, templates,\nclick events, and element IDs.\n\nCore changes:\n- Add setIndexMapFn to PluginContext — plugins can register a render→logical\n  index mapper that the pipeline us\n[…]\n.ts (engine.ts is now pure math)\n\nAlso fixes:\n- groups-table-data flaky tests: scoped ensureDimensions() helper\n- renderer.test.ts: instance-level clientWidth/Height override\n\n3815 tests pass, 0 fail.",
          "is_bot": false,
          "headline": "fix(carousel): virtual indices no longer leak into public API",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T16:34:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "243d62ffe7e742411be4d4bc0fb28f076451b32d",
          "body": "- Add gap parameter to LayoutConfig — engine subtracts gap from slot widths\n  and adds spacing in offset accumulation. Both axes, all variants.\n- Center-aligned hero: getAnchorOffset() shifts viewport anchor for pre-focal\n  slots so the focal item is visually centered.\n- Full preset now uses the engine (slots: [1.0]) — no special case.\n- Default gap: 0 (library convention). Example sets gap: 8 (MD3 spec).\n- 62 tests: 3 gap tests (hero/full/vertical), 1 center centering test.",
          "is_bot": false,
          "headline": "feat(carousel): gap support, center preset, all variants through engine",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T15:04:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9f9789e8a3662d9e3b36098813e543528a5a636f",
          "body": "Slot-based layout model: each variant is a configuration of slot\nratios (e.g., hero [0.80, 0.20], center [0.15, 0.70, 0.15]).\nThe engine computes per-item sizes, offsets, and CSS variables\nfrom the scroll fraction — all variants use the same code path.\n\n- engine.ts: createLayoutEngine(), resolveVari\n[…]\n MD3 transition model: outgoing shrinks to 0, incoming grows, next peek fades in\n- Snap-on-idle via setTimeout in onAfterScroll\n- next()/prev() always target snap positions\n- 58 tests, +2.1 KB gzipped",
          "is_bot": false,
          "headline": "refactor(carousel): extract layout engine into engine.ts",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T14:19:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0e74188a28503ce3e4eba725dd3e47650647fca0",
          "body": "…riables\n\nPhase 2 implementation:\n- Compute step size per variant (full=container, hero=container-peek, hero-center=container-2*peek)\n- Resolve peek from number (px), percentage string, or \"auto\" (56dp, clamped 40-56)\n- Set --vlist-carousel-progress, --vlist-carousel-offset, --vlist-carousel-role per element on scroll\n- 56 tests covering step size, peek config, CSS variables, hero cycling and infinite loop",
          "is_bot": false,
          "headline": "feat(carousel): hero/hero-center variants with peek sizing and CSS va…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T12:24:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "032f8f9e53b2d3c4a24cf6ad236e6288bc09240c",
          "body": "The onAfterScroll hook now emits a carousel:change event with the\nlogical index when the focused card changes from user scrolling.\nConsumers can listen to update dots, panels, or other UI.",
          "is_bot": false,
          "headline": "feat(carousel): emit carousel:change event on scroll index change",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T11:18:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e3bb7ac8648b3e4602df16220882f140753739b7",
          "body": "The first render happened at scrollPosition=0 (items at indices 0-5).\nThe onCommit hook then set scrollTop to 384,000 but the DOM still\nshowed the stale items. Now forces a re-render after setting the\ninitial scroll position.\n\nAlso removed the sizeCache.rebuild hook that was corrupting realTotal\nwhen the engine called rebuild(virtualTotal) internally.\n\nPublic API (list.total) returns realTotal via virtualTotalFn.\nengineState.totalItems is virtualTotal for the render pipeline.",
          "is_bot": false,
          "headline": "fix(carousel): render items at correct virtual positions",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T11:11:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e851c97e97f77c8282b896a0a0f18c034ce4d713",
          "body": "The virtual scroll window is now entirely internal to the sizeCache\nhooks — getTotalSize, getOffset, getSize, indexAtOffset, and getTotal\nall report virtual dimensions, but engineState.totalItems stays at\nthe real item count.\n\nThis means ARIA, selection, click events, and list.total all see the\nlogical 16 items, not the inflated 1616 virtual slots. Matches the\nRFC-011 spec: \"Public totals stay logical.\"",
          "is_bot": false,
          "headline": "fix(carousel): keep totalItems at real count, hook sizeCache internally",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T10:56:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a5b8681df34363446656319bb063979b2e48423f",
          "body": "…integration\n\n- sizeCache rebuilt with virtualTotal for proper content height\n- Initial scroll to middle cycle deferred to onCommit hook\n- next()/prev() scroll forward/backward from current position\n- goTo() uses shortest-path in virtual space\n- scrollToIndex override for wrap-aware navigation\n- Plugin-wizard example updated to use carousel() plugin\n- Verified in browser: forward wrap from last→first works\n- 26 tests, +1.0 KB gzipped, 18 size scenarios clean",
          "is_bot": false,
          "headline": "feat(carousel): virtual scroll window with deferred init and browser …",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T10:47:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "32d60ebca4e0411e120a9f857af26f8a68a961a4",
          "body": "- 101-cycle virtual window: items mapped via modulo, start in middle cycle\n- Silent rebasing when approaching edge cycles (threshold: 10 cycles)\n- next()/prev() always scroll in the user's direction (no rewind)\n- goTo() with direction: auto takes shortest path, forward/backward forced\n- Smooth scroll with easeInOutQuad animation\n- scrollToIndex override for wrap-aware navigation\n- onAfterScroll hook updates currentIndex from scroll position\n- +1.0 KB gzipped (within 2.0 KB budget)",
          "is_bot": false,
          "headline": "feat(carousel): virtual scroll window with silent rebasing",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T10:28:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9141a5bd61f3b384850d3d54688608e0f45eee56",
          "body": "…tests\n\n- Export carousel from src/index.ts\n- Add to build.ts ALL_PLUGINS and wrapper\n- Add size scenario: +0.4 KB gzipped (18 scenarios clean)\n- Add tests: virtual item mapping (modulo wrap), next/prev cycling\n  across boundaries, initialIndex with wrapping\n- 26 tests passing",
          "is_bot": false,
          "headline": "feat(carousel): export, build entry, size tracking, and virtual item …",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T10:17:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3f9d8caa0d5f250706b7d0239e096dbee09dc0aa",
          "body": "Carousel plugin stub with 21 passing tests covering:\n- Factory (name, priority, variants, scale conflict)\n- Registered methods (next, prev, goTo, getCarouselState)\n- Infinite loop (wrap forward/backward, step with wrap)\n- Logical totals (real item count, index always 0..total-1)\n- Edge cases (empty list, single item)\n- Snap config, variant: full, goTo direction, destroy\n\nImplementation uses modulo index resolution and shortest-path\nnavigation. Silent rebasing and CSS variable effects are next.",
          "is_bot": false,
          "headline": "feat(carousel): scaffold plugin with tests-first (RFC-011)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T10:08:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "261a5f26ff1efbf815f0fa59d7167d218efd2e33",
          "body": "…clamp\n\nscrollToIndex clamped indices to 0..total-1, ignoring the scroll.wrap\nconfig. Index 16 with 16 items was clamped to 15 — no scroll happened.\nNow uses modulo when wrap is enabled, matching the JSDoc contract.",
          "is_bot": false,
          "headline": "fix(core): scrollToIndex respects scroll.wrap with modulo instead of …",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-06T09:05:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ded39a4b2d6645dc83743e300782e6064f22bc03",
          "body": "chore(release): v2.3.0",
          "is_bot": false,
          "headline": "Merge pull request #104 from floor/staging",
          "author_name": "Floor",
          "author_login": "floor",
          "committed_at": "2026-06-05T14:38:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "57c840a9b6135e51f8699b6cc50d05cb886fd15d",
          "body": "Add tests for keyboard handler (open/close/navigate), cancel timeout,\nand type-ahead invisible mode (position: \"none\"). Coverage goes from\n81.1% to 87.2% line coverage.",
          "is_bot": false,
          "headline": "test(search): raise coverage above 85% threshold",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T14:17:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b7d983f46ab58ed3e9a2c6d60fae57bcd8794e9d",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v2.3.0",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T13:55:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1be82f946365a9b06f2f7f9b31d4037e433d24d3",
          "body": null,
          "is_bot": false,
          "headline": "docs(release): prepare v2.3.0 notes, README/npm-readme sizes and version",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T13:54:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a6a16ef2d2657168a82765cfe50908bf020ed212",
          "body": "The groups plugin's rebuild hook was destroyed when the table plugin\ncalled setSizeConfig (Object.assign overwrites all sizeCache methods).\nThe previous fix used queueMicrotask to re-hook, which only worked\nfor autoLoad:true due to timing.\n\nThe hook now self-heals: on each call, it checks if sizeCache.rebuild\nstill points to itself. If not (setSizeConfig overwrote it), it\nre-captures the new base and re-installs — same pattern as the grid\nplugin's installRebuildHook guard.\n\nResolves issue 022.",
          "is_bot": false,
          "headline": "fix(groups): self-healing sizeCache.rebuild hook survives setSizeConfig",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T13:40:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0071b1cd643199a74cf6002ba8aa1f40471d68cc",
          "body": "…tive\n\nWhen primary axis is X and a sticky header exists, inline group headers\nwere still rendered and visible alongside the sticky header. Now sets\ndisplay:none on inline headers in this case — the sticky header alone\nhandles group labeling in horizontal scrolling mode.",
          "is_bot": false,
          "headline": "fix(groups): hide inline headers in horizontal mode when sticky is ac…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T12:49:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "08fcf7ddd8162bbf6a93881cadb040d616fa6410",
          "body": "… mode\n\nlaneYCenters was populated with zeros when groups was active because\nthe groups layout positions aren't in cachedPlacements. The groups\nplugin now exposes _getItemY and _getItemH methods, and masonry uses\nthem to compute accurate Y-center values for bsNearest cross-lane\nnavigation.",
          "is_bot": false,
          "headline": "fix(masonry,groups): ArrowRight/Left finds nearest Y-center in groups…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T12:36:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "26b8b26618ba3c85871da6dcb504b1be049060fe",
          "body": "…o-view\n\nThe groups plugin's _scrollItemIntoView used sizeCache.getSize()\nwhich returns fallback heights in masonry mode, not the computed\nmasonry item height. Now reads pos.h from gridItemPositions.\n\nAlso accounts for startPadding in the scroll-up detection so the\nfocused item doesn't touch the viewport top edge.",
          "is_bot": false,
          "headline": "fix(groups): use actual item height and padding in masonry scroll-int…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T12:17:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d04e8d8f7eed5d1914f4cad62b36530bbbff6135",
          "body": "The masonry navigate() function receives layout indices from the\nselection plugin, but cachedPlacements uses data indices. When groups\nis active, these differ because group headers are interleaved.\n\nAdded toData/toLayout helpers that resolve _layoutToDataIndex and\n_dataToLayoutIndex from the groups \n[…]\noutToDataIndex\n(the groups plugin's masonry integration path skips it), so the\nconversion is identity for now. The framework is in place for when\ngroups properly exposes index mapping in masonry mode.",
          "is_bot": false,
          "headline": "fix(masonry): add layout↔data index conversion for groups compatibility",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T12:03:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e88e6b8c128d55e45b331902f54d16d875e54ce2",
          "body": "selection and scale referenced \"getGridLayout\" (a public grid method)\nto read the row gap, causing the size checker to flag grid code as\nleaked into their bundles.\n\nGrid now registers a private _getRowGap method. Selection and scale\nread it via ctx.getMethod(\"_getRowGap\") — no grid-specific string\nin their source, clean tree-shaking.",
          "is_bot": false,
          "headline": "fix(grid,scale,selection): use _getRowGap to avoid tree-shaking leak",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T11:07:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "82097c73b9e6a5cbbc28ed67ebeb78c8297372f9",
          "body": "Use startPadding/endPadding individually instead of mainAxisPadding.\nThe compressed path computes a delta from the item's actual rendered\nposition (via calculateCompressedItemPosition) relative to the\nviewport, then adjusts the virtual scroll by delta * ratio.\n\nNon-compressed paths in both selection and scale now include\nstartPadding in the scroll-down target so the bottom gap matches\nendPadding exactly.",
          "is_bot": false,
          "headline": "fix(scale,selection): pixel-perfect scroll-into-view with padding",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T10:59:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "78f0458f0e4ddb49ede691f24d8a9b0ba87119aa",
          "body": "The compressed path compared virtual item positions against the\nviewport size (an actual-pixel measurement), mixing coordinate\nspaces. ArrowDown from the top at 500K+ never triggered scrolling\nbecause the virtual positions were far smaller than containerSize.\n\nNow uses calculateCompressedItemPosition to get the item's rendered\noffset relative to the viewport, then compares against containerSize\ndirectly — same logic as the non-compressed path.",
          "is_bot": false,
          "headline": "fix(scale): use actual item position for scroll-into-view detection",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T10:11:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "edfd39a0ecab6e7eae829aa847461e87dc1d19d6",
          "body": "scrollFocusIntoView and _scrollItemIntoView positioned the last item\nflush against the viewport edge, ignoring mainAxisPadding. The bottom\npadding was invisible when pressing End or ArrowDown to the last item.\n\nSelection plugin now checks `offset + size > sp + cs - pad` and\nscrolls to `offset + size + pad - cs`.\n\nScale plugin adds `mainAxisPadding * ratio` to getMaxScroll so the\ncompressed scroll range includes the scaled padding. The non-compressed\npath mirrors the selection plugin's formula.",
          "is_bot": false,
          "headline": "fix(scale,selection): account for padding in scroll-into-view",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T09:56:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a5108a4b0d19ccf300519ff1509a6fb264724687",
          "body": "Grid: verify updateGrid survives rapid column/gap changes without\nstack overflow, and that the rebuild hook uses the mutable column\ncount (not the stale initial config).\n\nScale: _scrollItemIntoView and scrollToIndexFn tests were added in\nthe prior commit (a9ddd53).",
          "is_bot": false,
          "headline": "test(grid,scale): add tests for rebuild hook and scroll-into-view",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T08:45:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0683af3557060ee2ec14d183f9ce686e470bb970",
          "body": "installRebuildHook captured sizeCache.rebuild which was already the\nhooked version when called without a preceding setSizeConfig — the\nhook called rebuildAsRows which called the hook again.\n\nNow tracks the current hook reference and skips re-installation if\nsizeCache.rebuild is already hooked.",
          "is_bot": false,
          "headline": "fix(grid): prevent infinite recursion in sizeCache.rebuild hook",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T08:41:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a9ddd536f58c98079f7e64982d9cbe26536dddc4",
          "body": "The selection plugin's scrollFocusIntoView compared uncompressed\nsizeCache offsets against the compressed virtual scroll position —\ndifferent coordinate spaces. This caused ArrowUp from the bottom\nof a scaled list to leave the focused item pinned at the viewport\nbottom instead of scrolling up.\n\nThe scale plugin now registers _scrollItemIntoView which uses\ncalculateCompressedScrollToIndex to compute the correct virtual\nposition for both \"item above viewport\" and \"item below viewport\"\ncases.",
          "is_bot": false,
          "headline": "fix(scale): register _scrollItemIntoView for keyboard navigation",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T08:18:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "55c4589911d78835dc81c771599f59fa2bfcd488",
          "body": "The data plugin calls sizeCache.rebuild(itemCount) when data loads.\nWithout the hook, this overwrites the grid's row-based total with the\nraw item count, breaking the scale plugin's compression ratio and\nscrollbar range.\n\nThe hook converts item count → row count (ceil(n / columns)) before\ndelegating\n[…]\nevery\nsetSizeConfig call (which Object.assigns a new cache and destroys\nhooks).\n\nAlso adds onContentKeydown input guard in create.ts to skip keydown\nfor embedded form controls (input/textarea/select).",
          "is_bot": false,
          "headline": "fix(grid): hook sizeCache.rebuild to convert item count to row count",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-05T03:44:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dbf2f318b11b17f18f1e13feda50c1f567228c0e",
          "body": "…pping\n\nresolveClickedItem maps layout index → data index via _layoutToDataIndex\nwhen groups are active. Previously it passed the data index to getItemFn,\nwhich in table+groups mode is already layout-aware (set by the groups\nplugin via setGetItemFn) — causing a double mapping that returned the\nwrong\n[…]\nfor the\ntable-mode ordering requirement (groups must be pushed after table in\nthe plugin array since both are priority 10).\n\nTests: item:click offset correctness with groups, header click suppression.",
          "is_bot": false,
          "headline": "fix(core): resolveClickedItem uses _getItem to avoid double layout ma…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-04T10:41:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "20a359523abc9345fa666ae6c2a23c78ff425361",
          "body": "Search plugin (RFC-008 Phase 1), scoped highlighting, tree+selection\nclick fixes, and stale-mark highlight fix.",
          "is_bot": false,
          "headline": "Merge feat/search-plugin into staging",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-04T08:19:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9969ac699004001ac3025ffbdb7618f26494ce78",
          "body": "forceRender() reuses pooled elements without re-rendering templates\nwhen the same item stays at the same index (pipeline.ts:306). This\nleft <mark> tags from the previous query in the DOM; the TreeWalker\nthen skipped text inside those marks, producing partial highlights.\n\nhighlightElement now calls clearHighlights first to unwrap existing\nmarks and restore original text nodes before applying the new query.",
          "is_bot": false,
          "headline": "fix(search): clear stale marks before re-highlighting on each keystroke",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-04T04:27:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1e1f752320047145d5c7ad5ce841480a75473772",
          "body": "The `highlight` option now accepts `{ within: \".selector\" }` to\nrestrict `<mark>` wrapping to matching descendants instead of the\nwhole row. Prevents false highlights when the query appears in\nunrelated fields.\n\nAlso adds border-bottom to MD3 search bar variant.",
          "is_bot": false,
          "headline": "feat(search): scoped highlighting via highlight.within selector",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-04T03:59:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d47456fcbe02b5e04dc9a586adaacf49c984dbce",
          "body": "Selection click handler used doToggle() in single mode, causing\nre-clicks to deselect. Now uses doSelect() so single-mode clicks\nalways select.\n\n_focusById now sets focusVisible = focusOnClick so the --focused\nCSS class appears when the tree plugin delegates focus.\n\nTree plugin registers _getLoadedI\n[…]\neyond root-level indices.\n\nAlso improves groups-table-data test resilience under --concurrent\nby documenting the Bun shared-heap prototype race and re-installing\noverrides at the snapshot-restore gap.",
          "is_bot": false,
          "headline": "fix(selection,tree): consistent click selection in tree views",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-04T03:59:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "15e6db0f35bdafe50bad673cbef3dd2cb0a84c1f",
          "body": "selection/a11y: add keyboard?: boolean (default true). When false, the\nkeydown handler is skipped — click-selection, focus, and the full\nselection model stay active, letting an outer system own keyboard\nnavigation (e.g. a global, focus-independent hotkey layer).\n\ncore: resolveClickedItem maps layout\n[…]\nre (was falling back to the empty static\nitems array, always returning -1).\n\nNOTE: programmatic selectNext/selectPrevious scroll-into-view at the\nviewport edge is a known open issue (see desk issues).",
          "is_bot": false,
          "headline": "feat(selection): add keyboard option, fix getIndexById for async data",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-03T00:01:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "efa604f8510236fd4b34a8d2c0e3a1d435c41557",
          "body": null,
          "is_bot": false,
          "headline": "docs(contributing): add no-inline-text standard (RFC-010)",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-02T18:44:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "77b6fae6bf758ebf3ff23a7c3d231dfc887ac613",
          "body": "…010)\n\nRestructure the search bar to a modular BEM DOM (.vlist-search__container /\n__leading-icon / __input / __counter / __nav-prev|next / __clear-button) and\nrewrite the styles to BEM with theme tokens (reuse base --vlist-* vars; only\nmatch-highlight + MD3 surface/state are search-specific).\n\nExte\n[…]\nd the former top-level\nplaceholder option into text.placeholder.\n\nAdds RFC-010 test coverage (decorative magnifier, unnamed/named landmark,\nconsumer labels + counter formatters). 32 search tests pass.",
          "is_bot": false,
          "headline": "refactor(search): modular BEM search bar + externalized UI text (RFC-…",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-02T18:44:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cdd1388b02c96dc9f5ac99da0d9b9e5c6acd5776",
          "body": null,
          "is_bot": false,
          "headline": "docs(search): list search() in README + npm-readme plugin tables",
          "author_name": "DrJones",
          "author_login": "drjonze",
          "committed_at": "2026-06-02T15:19:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 34,
      "commits_last_year": 1864,
      "latest_release_at": "2026-07-15T05:46:50Z",
      "latest_release_tag": "v2.6.1",
      "releases_from_tags": false,
      "days_since_last_push": 9,
      "active_weeks_last_year": 22,
      "days_since_latest_release": 9,
      "mean_days_between_releases": 4.8
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 57,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "vlist",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "virtual-list",
            "virtual-scroll",
            "virtualized-list",
            "infinite-scroll",
            "windowing",
            "list-virtualization",
            "dom-recycling",
            "large-list",
            "performance",
            "typescript",
            "zero-dependencies"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/vlist",
          "is_deprecated": false,
          "latest_version": "2.6.1",
          "repository_url": "https://github.com/floor/vlist",
          "versions_count": 47,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1016,
          "first_published_at": "2017-07-07T07:59:07.048000Z",
          "latest_published_at": "2026-07-15T05:46:47.346000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 9
        },
        {
          "name": "@floor/vlist",
          "exists": true,
          "license": "MIT",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@floor/vlist",
          "is_deprecated": true,
          "latest_version": "1.5.6",
          "repository_url": "https://github.com/floor/vlist",
          "versions_count": 68,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": "This package has moved to 'vlist'. Install with: npm install vlist",
          "maintainers_count": 2,
          "monthly_downloads": 209,
          "first_published_at": "2026-02-16T11:04:41.688000Z",
          "latest_published_at": "2026-04-15T16:22:52.852000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 99
        }
      ]
    },
    "popularity": {
      "forks": 1,
      "stars": 12,
      "watchers": 1,
      "fork_history": {
        "days": [
          {
            "date": "2026-04-11",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 1,
        "total_forks": 1
      },
      "star_history": null,
      "open_issues_and_prs": 11
    },
    "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": [
        "tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 80649,
      "source_files_sampled": 201,
      "oversized_source_files": 7,
      "agent_instruction_files": [
        ".claude/CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 12228
    },
    "dependencies": {
      "manifests": [
        "package.json",
        "shim/package.json"
      ],
      "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": 7,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "vlist",
          "manifest": "shim/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.5.5"
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "vlist",
            "direct": true,
            "version": "^1.5.5",
            "ecosystem": "npm"
          },
          {
            "name": "@happy-dom/global-registrator",
            "direct": false,
            "version": "^20.9.0",
            "ecosystem": "npm"
          },
          {
            "name": "@types/bun",
            "direct": false,
            "version": "^1.0.0",
            "ecosystem": "npm"
          },
          {
            "name": "@types/jsdom",
            "direct": false,
            "version": "^27.0.0",
            "ecosystem": "npm"
          },
          {
            "name": "happy-dom",
            "direct": false,
            "version": "^20.9.0",
            "ecosystem": "npm"
          },
          {
            "name": "jsdom",
            "direct": false,
            "version": "^28.0.0",
            "ecosystem": "npm"
          },
          {
            "name": "typescript",
            "direct": false,
            "version": "^5.0.0",
            "ecosystem": "npm"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 7,
        "direct_count": 1,
        "indirect_count": 6
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 48,
        "open_issues": 11,
        "closed_ratio": 0.8,
        "closed_issues": 44,
        "closed_unmerged_prs": 1
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "drjonze",
          "commits": 1798,
          "avatar_url": "https://avatars.githubusercontent.com/u/150515870?v=4"
        },
        {
          "type": "User",
          "login": "floor",
          "commits": 66,
          "avatar_url": "https://avatars.githubusercontent.com/u/187733?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.965
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ai-committee.yml",
        "ci.yml",
        "notify-staging.yml",
        "publish.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": null,
            "reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "6 out of 6 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/6 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 30 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": "internal error: Client.Actions.ListWorkflowRunsByFileName: internal error: ListWorkflowRunsByFileName: GET https://api.github.com/repos/floor/vlist/actions/workflows/publish.yml/runs?status=success: 502 Server Error []",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 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": 0,
            "reason": "12 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "7c39284b964a4d4e7b67821d17a622cf599eaed8",
        "ran_at": "2026-07-24T16:12:47Z",
        "aggregate_score": 3.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-18T12:58:12Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-15T05:45:44Z",
      "ci_last_conclusion": "SKIPPED",
      "oldest_open_issues": [
        {
          "number": 20,
          "created_at": "2026-04-14T06:26:09Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 25,
          "created_at": "2026-04-14T09:41:28Z",
          "last_comment_at": "2026-06-10T06:50:16Z",
          "last_comment_author": "AzzaAzza69"
        },
        {
          "number": 31,
          "created_at": "2026-04-20T06:55:49Z",
          "last_comment_at": "2026-06-02T07:28:40Z",
          "last_comment_author": "AzzaAzza69"
        },
        {
          "number": 47,
          "created_at": "2026-05-01T08:36:44Z",
          "last_comment_at": "2026-05-29T09:29:57Z",
          "last_comment_author": "AzzaAzza69"
        },
        {
          "number": 60,
          "created_at": "2026-05-13T14:12:23Z",
          "last_comment_at": "2026-06-06T11:00:10Z",
          "last_comment_author": "AzzaAzza69"
        },
        {
          "number": 101,
          "created_at": "2026-06-02T07:22:57Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 106,
          "created_at": "2026-06-06T11:02:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 113,
          "created_at": "2026-06-10T06:38:31Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 114,
          "created_at": "2026-06-10T06:41:19Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 115,
          "created_at": "2026-06-10T06:42:29Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 116,
          "created_at": "2026-06-10T07:14:16Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/floor/vlist",
    "host": "github.com",
    "name": "vlist",
    "owner": "floor"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 59,
      "inputs": {
        "security": 36,
        "vitality": 83,
        "community": 44,
        "governance": 54,
        "engineering": 71
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 83,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "commits_last_year": 1864,
              "human_commit_share": 1,
              "days_since_last_push": 9,
              "active_weeks_last_year": 22
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 9 days ago",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 9
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "22/52 weeks with commits",
                "points": 15.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 22
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "1864 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 1864
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "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": 100,
            "inputs": {
              "releases_count": 34,
              "latest_release_tag": "v2.6.1",
              "releases_from_tags": false,
              "days_since_latest_release": 9,
              "mean_days_between_releases": 4.8
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "34 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 34
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 9 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 9
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~4.8 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 4.8
                    }
                  }
                ],
                "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": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "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": 44,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 17,
            "inputs": {
              "forks": 1,
              "stars": 12,
              "watchers": 1,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "12 stars",
                "points": 16.9,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 12
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "1 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "1 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 70,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "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": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "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": 52,
            "inputs": {
              "packages": [
                "vlist",
                "@floor/vlist"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 1225
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "1,225 downloads/month across npm",
                "points": 41.2,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 1225,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "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": 54,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 16,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.965
            },
            "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 96% of commits",
                "points": 0.8,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 96
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "2 contributors",
                "points": 2.7,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "merged_prs": 48,
              "open_issues": 11,
              "closed_issues": 44,
              "issue_closed_ratio": 0.8,
              "closed_unmerged_prs": 1
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "80% of issues closed",
                "points": 37.4,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 80
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "48/49 decided PRs merged",
                "points": 37.5,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 48,
                      "decided": 49
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/6 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 57,
            "inputs": {
              "followers": 53,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "floor",
              "public_repos": 30,
              "account_age_days": 6027
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "53 followers of floor",
                "points": 12.5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 53,
                      "login": "floor"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "30 public repos, account ~16 yr old",
                "points": 22.9,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 30
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 16
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "good",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "packages": [
                "vlist",
                "@floor/vlist"
              ],
              "ecosystems": "npm",
              "any_deprecated": true,
              "min_days_since_publish": 9
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "2 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 2,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 9 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 9
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "68 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 68
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "@floor/vlist: This package has moved to 'vlist'. Install with: npm install vlist",
                "points": 0,
                "status": "missed",
                "details": [],
                "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": 71,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "4 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "6 out of 6 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [
                "lightweight",
                "performance",
                "typescript",
                "virtual-list",
                "virtual-scroll",
                "virtualization",
                "zero-dependencies"
              ],
              "has_wiki": true,
              "homepage": "https://vlist.io",
              "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": "https://vlist.io",
                "points": 15,
                "status": "met",
                "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": "7 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "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": 36,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Branch-Protection, Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "branch_protection",
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 36,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 15,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 3,
              "scorecard_aggregate": 3.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": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "6 out of 6 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/6 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 30 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": "internal error: Client.Actions.ListWorkflowRunsByFileName: internal error: ListWorkflowRunsByFileName: GET https://api.github.com/repos/floor/vlist/actions/workflows/publish.yml/runs?status=success: 502 Server Error []",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "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": "12 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "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": 2
            },
            "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": 64,
        "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.97,
              "agent_instruction_files": [
                ".claude/CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 12228
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": ".claude/CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".claude/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": "97 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 97,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 35,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "tsconfig.json"
              ],
              "agent_commit_share": 0.01,
              "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "tsconfig.json"
                    }
                  }
                ],
                "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": "1 of the last 100 commits agent-authored or agent-credited",
                "points": 2,
                "status": "partial",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 1,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 98,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 80649,
              "source_files_sampled": 201,
              "oversized_source_files": 7
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "TypeScript (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "TypeScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "7/201 source files over 60KB",
                "points": 53.1,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 201,
                      "oversized": 7
                    }
                  }
                ],
                "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-24T16:13:13.749583Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/f/floor/vlist.svg",
  "full_name": "floor/vlist",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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