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

hihaho / phpstan-rules

Hihaho PHPStan rules according to our guidelines

PHPMIT★ 7 星标⑂ 1 复刻始于 2023年9月在 GitHub 上查看 ↗

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

65
总分 / 100
中等

软件健康指数

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

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

评分画像

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

所有权

hihaho组织
5 关注者9 个公开仓库始于 2017年9月

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布
Packagisthihaho/phpstan-rulesv3.14.05,2963121 天前

按类别列示的指标

活力

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

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

发布纪律

100优秀
评分方式
27/27有发布版本 — 已发布 31 个发布版本
36/36发布时效 — 最近一次发布版本于 20 天前
27/27发布节奏 — 约每 2.3 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count31
latest_release_tagv3.14.0
releases_from_tags
days_since_latest_release20
mean_days_between_releases2.3
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

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

44存在风险 · 占总体的 18%
评分方式
12.6/60星标 — 7 个星标
0/25复刻 — 1 个复刻
3.3/15关注者 — 5 位关注者
所用输入
forks1
stars7
watchers5
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
评分方式
49.7/80月度下载量 — packagist 合计每月 5,296 次下载
2/20注册表被依赖数 — 1 个软件包依赖它
所用输入
packageshihaho/phpstan-rules
dependents1
ecosystemspackagist
total_downloads52,119
monthly_downloads5,296

可持续性与治理

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

60中等 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
7.4/22.5提交分布 — 头号贡献者编写了 67% 的提交
4.1/13.5贡献者广度 — 3 位贡献者
10/10OpenSSF Scorecard:Contributors — project has 4 contributing companies or organizations
所用输入
bus_factor1
contributors_sampled3
top_contributor_share0.673
评分方式
0/46.8议题解决 — 没有议题或无数据
36.1/38.3PR 接受 — 已裁定的 PR 中 83/88 已合并
0/15OpenSSF Scorecard:Code-Review — Found 0/15 approved changesets -- score normalized to 0
所用输入
merged_prs83
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs5
已排除计分(无数据或不适用):议题解决。 其余权重已重新归一化。
评分方式
30/30所有权背书 — 组织持有
0/20已验证域名
5.6/25所有者影响力 — hihaho 有 5 位关注者
19.3/25既往记录 — 9 个公开仓库,账户约 8 年
所用输入
followers5
owner_typeOrganization
is_verified
owner_loginhihaho
public_repos9
account_age_days3,245
评分方式
25/25已发布且可解析 — packagist 上有 1 个软件包
35/35发布时效 — 最近一次发布于 21 天前
20/20版本历史 — 31 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packageshihaho/phpstan-rules
ecosystemspackagist
any_deprecated
min_days_since_publish21

工程质量

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

66中等 · 占总体的 20%

工程实践

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

文档

55中等
评分方式
30/30README
0/25文档目录
15/15文档 / 主页站点 — https://guidelines.hihaho.com
10/10仓库描述
0/10主题标签
0/10Wiki
所用输入
topics
has_wiki
homepagehttps://guidelines.hihaho.com
has_readme
has_docs_dir
has_description

安全

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

67中等 · 占总体的 16%

安全态势

67中等
评分方式
7.5/7.5Binary-Artifacts — no binaries found in the repo
4.5/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 25 out of 25 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/15 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 4 contributing companies or organizations
0/10Dangerous-Workflow — 无数据
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — 无数据
0/5Pinned-Dependencies — 无数据
5/5SAST — SAST tool is run on all commits
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — 无数据
0/7.5Token-Permissions — 无数据
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated13
scorecard_versionv5.5.0
checks_inconclusive5
scorecard_aggregate6.7
已排除计分(无数据或不适用):dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions。 其余权重已重新归一化。

AI 就绪度

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

54中等 · 占总体的 0%
评分方式
45/45代理指令 — .github/copilot-instructions.md, AGENTS.md, CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 75 次人类提交中有 64 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.853
agent_instruction_files.github/copilot-instructions.md, AGENTS.md, CLAUDE.md
agent_instruction_max_bytes12,530
评分方式
0/18一条命令的引导启动
22/22自动化测试
0/11Lint / 格式化配置
0/11静态类型检查
0/10可复现环境
10/10已体现的代理实践 — 最近 100 次提交中有 9 次由代理编写或署名代理
8/8自动化维护 — 最近 100 次提交中有 8 次为自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — 无数据
所用输入
has_nix
has_tests
lockfiles
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0.09
toolchain_manifests
dependency_bot_commit_share0.08
已排除计分(无数据或不适用):OpenSSF Scorecard:Pinned-Dependencies。 其余权重已重新归一化。
评分方式
0/45可类型检查的代码 — PHP,未配置类型检查
55/55可控的文件大小 — 采样的 193 个源文件中有 0 个超过 60KB
所用输入
primary_languagePHP
largest_source_bytes17,604
source_files_sampled193
oversized_source_files0
评分方式
0/40API 模式(OpenAPI/GraphQL/proto)
20/20MCP 服务器
0/40可运行示例
所用输入
example_dirs
has_mcp_signal
api_schema_files

关键数据

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

数据采集警告

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

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

10Binary-Artifactsno binaries found in the repo
6Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests25 out of 25 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/15 approved changesets -- score normalized to 0
10Contributorsproject has 4 contributing companies or organizations
不适用Dangerous-Workflowno workflows found
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
不适用Packagingpackaging workflow not detected
不适用Pinned-Dependenciesno dependencies found
10SASTSAST tool is run on all commits
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
不适用Token-PermissionsNo tokens found
10Vulnerabilities0 existing vulnerabilities detected
直接依赖 3
注册表软件包版本约束清单文件
Packagistilluminate/database^12.0||^13.0composer.json
Packagistilluminate/http^12.0||^13.0composer.json
Packagistilluminate/support^12.0||^13.0composer.json
全部依赖 25

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

注册表软件包版本关系
Packagistilluminate/database直接
Packagistilluminate/http直接
Packagistilluminate/support直接
Packagistlarastan/larastan间接
Packagistlaravel/pao间接
Packagistlaravel/pint间接
Packagistnikic/php-parser间接
Packagistnunomaduro/collision间接
Packagistorchestra/testbench间接
Packagistphp间接
Packagistphpstan/extension-installer间接
Packagistphpstan/phpstan间接
Packagistphpstan/phpstan-deprecation-rules间接
Packagistphpstan/phpstan-phpunit间接
Packagistphpstan/phpstan-strict-rules间接
Packagistphpunit/phpunit间接
Packagistrector/rector间接
Packagistrector/type-perfect间接
Packagistsandermuller/boost-skills间接
Packagistsandermuller/package-boost-php间接
Packagistspatie/invade间接
Packagistspaze/phpstan-disallowed-calls间接
Packagistsymplify/phpstan-extensions间接
Packagisttomasvotruba/cognitive-complexity间接
Packagisttomasvotruba/type-coverage间接
依赖安全公告 未评估

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 565,
      "has_wiki": false,
      "homepage": "https://guidelines.hihaho.com",
      "languages": {
        "PHP": 295398,
        "Blade": 125
      },
      "pushed_at": "2026-07-28T13:02:05Z",
      "created_at": "2023-09-20T11:04:58Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-28T13:05:13Z",
      "description": "Hihaho PHPStan rules according to our guidelines",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "PHP",
      "significant_languages": [
        "PHP"
      ]
    },
    "owner": {
      "blog": "https://www.hihaho.com/",
      "name": "hihaho",
      "type": "Organization",
      "login": "hihaho",
      "company": null,
      "location": "Netherlands",
      "followers": 5,
      "avatar_url": "https://avatars.githubusercontent.com/u/31760627?v=4",
      "created_at": "2017-09-08T07:46:13Z",
      "is_verified": null,
      "public_repos": 9,
      "account_age_days": 3245
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v3.14.0",
          "kind": "minor",
          "published_at": "2026-07-07T15:53:26Z"
        },
        {
          "tag": "v3.13.0",
          "kind": "minor",
          "published_at": "2026-06-22T20:30:03Z"
        },
        {
          "tag": "v3.12.0",
          "kind": "minor",
          "published_at": "2026-06-22T16:40:28Z"
        },
        {
          "tag": "v3.11.2",
          "kind": "patch",
          "published_at": "2026-06-22T12:19:55Z"
        },
        {
          "tag": "v3.11.1",
          "kind": "patch",
          "published_at": "2026-06-22T11:44:59Z"
        },
        {
          "tag": "v3.11.0",
          "kind": "minor",
          "published_at": "2026-06-22T10:42:59Z"
        },
        {
          "tag": "v3.10.0",
          "kind": "minor",
          "published_at": "2026-06-22T09:12:15Z"
        },
        {
          "tag": "v3.9.0",
          "kind": "minor",
          "published_at": "2026-06-21T09:39:12Z"
        },
        {
          "tag": "v3.8.0",
          "kind": "minor",
          "published_at": "2026-06-21T08:10:12Z"
        },
        {
          "tag": "v3.7.0",
          "kind": "minor",
          "published_at": "2026-06-16T21:16:49Z"
        },
        {
          "tag": "v3.6.1",
          "kind": "patch",
          "published_at": "2026-06-14T16:52:03Z"
        },
        {
          "tag": "v3.6.0",
          "kind": "minor",
          "published_at": "2026-06-14T15:33:34Z"
        },
        {
          "tag": "v3.5.0",
          "kind": "minor",
          "published_at": "2026-06-14T13:22:12Z"
        },
        {
          "tag": "v3.4.1",
          "kind": "patch",
          "published_at": "2026-06-14T11:02:04Z"
        },
        {
          "tag": "v3.4.0",
          "kind": "minor",
          "published_at": "2026-06-13T22:59:03Z"
        },
        {
          "tag": "v3.3.0",
          "kind": "minor",
          "published_at": "2026-06-13T16:41:23Z"
        },
        {
          "tag": "v3.2.0",
          "kind": "minor",
          "published_at": "2026-06-09T17:21:15Z"
        },
        {
          "tag": "v3.1.2",
          "kind": "patch",
          "published_at": "2026-04-22T14:50:08Z"
        },
        {
          "tag": "v3.1.1",
          "kind": "patch",
          "published_at": "2026-04-22T14:42:38Z"
        },
        {
          "tag": "v3.1.0",
          "kind": "minor",
          "published_at": "2026-04-21T16:31:27Z"
        },
        {
          "tag": "v3.0.0",
          "kind": "major",
          "published_at": "2026-04-12T15:09:44Z"
        },
        {
          "tag": "v2.2.0",
          "kind": "minor",
          "published_at": "2026-03-01T16:13:28Z"
        },
        {
          "tag": "v2.1.0",
          "kind": "minor",
          "published_at": "2025-02-26T11:45:33Z"
        },
        {
          "tag": "v1.2.1",
          "kind": "patch",
          "published_at": "2024-12-11T15:25:49Z"
        },
        {
          "tag": "v2.0.1",
          "kind": "patch",
          "published_at": "2024-12-11T15:27:39Z"
        },
        {
          "tag": "v1.2.0",
          "kind": "minor",
          "published_at": "2024-12-11T14:01:21Z"
        },
        {
          "tag": "v2.0.0",
          "kind": "major",
          "published_at": "2024-11-27T12:40:55Z"
        },
        {
          "tag": "v1.1.1",
          "kind": "patch",
          "published_at": "2024-06-19T07:56:38Z"
        },
        {
          "tag": "v1.1.0",
          "kind": "minor",
          "published_at": "2024-06-18T07:59:16Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2024-05-02T11:38:35Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2023-09-20T13:28:32Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "4fafc86cb9e719d86102a0c9504ec09351481e55",
          "body": "AddSeeTestAnnotationRector writes the fully-qualified test class name;\nPint's fully_qualified_strict_types shortens it back; the next Rector run\nsees no FQCN and appends a duplicate. The two never converge, so\n`composer qa` reported drift on files nobody had touched. Skip the rule.\n\nAlso makes TraitRequiresInterfaceRule readonly, as Rector suggests once\nit stops rewriting that file's docblock.",
          "is_bot": false,
          "headline": "Stop Rector and Pint fighting over @see annotations",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-07-28T13:02:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9b2e9aba0a0b8050fee26ab2e031604be910153b",
          "body": "PHP cannot make a trait require an interface, so a trait and the contract\nit is meant to satisfy drift apart silently: classes pick up the trait's\nmethods without ever implementing the interface, and every tool that\nidentifies them by interface skips them.\n\nTraitRequiresInterfaceRule flags a class o\n[…]\nmeter, empty by default. A configured name that does not exist, or\nis not of the expected kind, aborts the analysis rather than matching\nnothing; names are matched case-insensitively, like PHP itself.",
          "is_bot": false,
          "headline": "Add rule requiring an interface alongside a trait",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-07-28T12:59:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9e2f2300478f63acde861357057d88dc45aae279",
          "body": "…5) (#88)\n\n* ci: trigger auto-fix on push instead of pull_request\n\nResolves CodeQL untrusted-checkout alert #15. The medium\nactions/untrusted-checkout rule fires on any explicit PR-head-ref\ncheckout (a step with ref: containing github.head_ref) in a\npull_request-triggered workflow — it has no permis\n[…]\nmmit straight to main.\n\nAlso folds in the pre-existing PHPStan-verify step that discards an\nauto-fix which would break static analysis before it is committed.\n\n* ci: tighten auto-fix workflow comments",
          "is_bot": false,
          "headline": "ci: trigger auto-fix on push to resolve CodeQL untrusted-checkout (#1…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-07-07T21:44:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "64d51dc73511f7d7f4b4c7668e2796f2ebe057d0",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.14.0 (#87)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-07T17:09:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4c9bc898792c20b79bcdb7ef2e18043bf18fcd20",
          "body": "Flags a non-empty $with property declared on an Eloquent Model. A\nmodel-level $with eager-loads its relations on every query for that\nmodel, globally and invisibly, inflating query counts across endpoints\nthat never need them. An explicit empty $with = [] is ignored, as is a\n$with property on any non-Model class.\n\nRegistered directly (property declarations are rare). Identifier:\nhihaho.conventions.noEloquentWithProperty.",
          "is_bot": false,
          "headline": "Add rule prohibiting Eloquent $with property",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-07-07T12:08:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2abfa1e679fdf631202877f276d34f8aa84639d7",
          "body": "Bumps [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action) from 7.1.0 to 7.2.0.\n- [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases)\n- [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.m\n[…]\nirect:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "build(deps): bump stefanzweifel/git-auto-commit-action (#86)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-02T06:39:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "386039a4267ec9bf9228791b55b20d49dcb7d065",
          "body": "Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.\n- [Release notes](https://github.com/actions/checkout/releases)\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/checkout/compare/v6...v7)\n\n---\nupdated-dependenc\n[…]\nirect:production\n  update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "build(deps): bump actions/checkout from 6 to 7 (#84)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-06-25T06:24:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "308901fb7e452f9af3c100a5c7f7d479a6524ce6",
          "body": "Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6.\n- [Release notes](https://github.com/actions/cache/releases)\n- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)\n- [Commits](https://github.com/actions/cache/compare/v5...v6)\n\n---\nupdated-dependencies:\n- dependenc\n[…]\nirect:production\n  update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "build(deps): bump actions/cache from 5 to 6 (#85)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-06-25T06:23:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "561b1323883770343b911cec052e73b50fef7ddf",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.13.0 (#83)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-22T20:43:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2eb0b0a9cf1b43558266fa005ec7f524913a97d9",
          "body": "A stubbedMethods return type of 'static', '$this', or 'self' now binds to\nthe receiver instead of being parsed as a PHPDoc type string, so a stubbed\nfluent method (a $this-returning macro, a chainable Nova field method)\nkeeps its chain typed instead of widening. Resolves the gap where\nself-returning framework methods couldn't be expressed as a fixed string.\n\nAlso adds an optional-{param?} implicit-binding fixture pinning the\ndocumented non-null over-claim.",
          "is_bot": false,
          "headline": "Add static/$this/self return marker to stubbedMethods (#82)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-22T20:28:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d7ef62058ac08ed9a70e31c3328af3e9b1b3b090",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.12.0 (#80)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-22T20:10:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a62c99c0b098fb4f29fa5e8f17461f09a7cadc2c",
          "body": "PHPStan's SimpleParser (the @currentPhpVersionSimpleDirectParser injected\ninto both route-binding resolvers) already runs NameResolver internally, so\nparsed class names come back fully qualified. The extra NameResolver\ntraversal was a no-op, and the comment claiming the parser does not resolve\nnames was wrong. Drop both.",
          "is_bot": false,
          "headline": "Remove redundant NameResolver pass from route-binding parsing (#81)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-22T20:05:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33f1f027b1c3ec89e734692357591b5d4ef1a63f",
          "body": "* Add implicit route-model binding resolution\n\nExtend RouteBindingReturnTypeExtension to resolve Laravel implicit\n(controller type-hint) route-model bindings, layered after the explicit\nRoute::model()/Route::bind() provider map. Retires route()+assert pairs\nfor parameters bound implicitly rather tha\n[…]\nassertions in CI. Keep the\nlarastan-loaded test asserting only the extension's own (version-stable)\noutput, and cover the skip/fail-safe cases in a Laravel-only test with a\nstable default type string.",
          "is_bot": false,
          "headline": "Add implicit route-model binding resolution (#79)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-22T16:37:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "594e6f66181ef5195af08386c92dc9da1742f7c8",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.11.2 (#78)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-22T12:29:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5d8aaf5c37f0d6627410b831d13a277a1509d222",
          "body": "…s (#77)\n\nAdd two README adoption notes, both surfaced by real consumer integration:\n- whereHas/relation closures: returning the narrowed builder trips a\n  return.type covariance error; use void block closures.\n- routeBindingProviders: once route('x') is typed, existing\n  assert($x instanceof Model)\n[…]\nroaden test fixtures: exercise the full relation-existence method\nfamily (orWhereDoesntHave/doesntHave/has with closures) and a Route::bind\nclosure with a built-in return type (skipped, not narrowed).",
          "is_bot": false,
          "headline": "Document route() assert-sweep and whereHas void-closure adoption note…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-22T12:17:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "28c15cad21b29be9300ad7b74535a58d3e9cb40f",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.11.1 (#76)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-22T11:53:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e06e0f460b4dcc529057b151f0f462ba397e5e49",
          "body": "v3.11.0 found zero bindings in any larastan-enabled app (i.e. every real\nLaravel project), silently leaving $request->route('x') as\nobject|string|null. Two root causes, both invisible to the package's own\ntest suite because it had no larastan installed:\n\n- larastan ships a DynamicMethodReturnTypeExt\n[…]\nsion WITH larastan loaded, so this can't regress silently. Exclude\nlarastan from the package's own analysis via the extension-installer\nignore list (it is only needed by the regression test's config).",
          "is_bot": false,
          "headline": "Fix RouteBindingReturnTypeExtension under larastan (#75)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-22T11:43:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0c52ada1b44fea69a30ef80d8e1f74451346c451",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.11.0 (#74)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-22T10:46:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "41c9213cb43cf8faeb79abea414c37f8de23ad24",
          "body": "* Add RouteBindingReturnTypeExtension\n\nType $this->route('x') / $request->route('x') as the model bound to the\nroute parameter, read from the configured route-service providers'\nRoute::model() and Route::bind() calls. Removes the repeated\nroute()+assert($x instanceof Model) pattern; the parameter na\n[…]\nosures with a T|null union return type (not only ?T).\n- Resolve class-constant route-parameter names (e.g. RouteParams::SUBTITLE),\n  via the constant's value expression so typed constants resolve too.",
          "is_bot": false,
          "headline": "Add route-model binding return type extension (#73)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-22T10:39:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1f6f3042a19c201d4bb359ea2e2e28865058c14f",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.10.0 (#72)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-22T09:15:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f9fed69a36a3123273885f216301843ee9061287",
          "body": "* Add RelationExistenceClosureBuilderParameterExtension\n\nInfer the related-model builder type for closures passed to Eloquent's\nrelationship-existence methods (whereHas/orWhereHas/whereDoesntHave/\norWhereDoesntHave/has/orHas/doesntHave/orDoesntHave) when the relation is\ngiven as a constant string. P\n[…]\n relation cannot be\n  proven, so genuine column typos still fail.\n- Declares illuminate/database, now used directly by the extension.\n\n* Document relation-existence closure builder extension in README",
          "is_bot": false,
          "headline": "Add relation-existence closure builder type extension (#71)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-22T08:58:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1e752bc30cf4f095ec583c3f67be0e315e7d8317",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.9.0 (#70)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-21T09:40:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3bc5796dd436e9f4124dc471e677db14292ebd23",
          "body": "Adds a DynamicMethodReturnTypeExtension that types Collection/LazyCollection ->values()->all() as list<TValue> instead of array<int, TValue>, restoring the JSON-array guarantee that the values() re-key provides at runtime.\n\nDetection is syntactic (direct ->values() receiver) and class-guarded (Support\\Collection/LazyCollection or subclass), so bare Enumerable and split-variable chains fail safe. Registered automatically; documented under a new README 'Return type extensions' section.",
          "is_bot": false,
          "headline": "Add CollectionListAllReturnTypeExtension (#68)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-21T09:30:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0f71d2ccdcc3a174ec692a4b3533e288972c889b",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.8.0 (#67)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-21T08:11:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d68150cd4684be34251cda73d7a6e85d2eec2b98",
          "body": "* Add StubbedMethodsClassReflectionExtension\n\nResolve methods that exist at runtime but not in PHPStan reflection — Faker\ncustom providers (added via __call), Laravel macros, facade __callStatic\nforwarding — so they no longer require a baseline entry, while a typo'd method\nname (not in the configure\n[…]\nrop stale 'facade __callStatic' mention from the stubbedMethods comment\n  to match the instance-only scope set in the rest of the PR\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add StubbedMethodsClassReflectionExtension (#66)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-21T08:05:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b4165abcce6892dbd2576fed3c3b978d1dfdebe3",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.7.0 (#65)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-16T21:26:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "db202f2fa990b99b081479507d698dbeac9e88e6",
          "body": null,
          "is_bot": false,
          "headline": "docs: note nested manifest outputPath auto-creates its directory",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-16T20:15:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "568df24d5faf374396967fb69214480abc626117",
          "body": "Lets consumers set a nested outputPath like .config/named-arguments-manifest.json;\nWriteNamedArgumentManifestRule now creates the parent directory before writing,\nsince file_put_contents does not create intermediate directories.",
          "is_bot": false,
          "headline": "feat: create manifest parent directory so nested output paths write",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-16T20:13:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7cab0b77923a91100bad28752ec32b717e2b3f6f",
          "body": "Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.37.1 to 2.37.2.\n- [Release notes](https://github.com/shivammathur/setup-php/releases)\n- [Commits](https://github.com/shivammathur/setup-php/compare/7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc...f3e473d116dcccaddc5834248c87\n[…]\nirect:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "build(deps): bump shivammathur/setup-php from 2.37.1 to 2.37.2 (#52)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-06-14T17:10:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "99d74a4e687de3aa3c298aef9da7a2a00d211582",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>\nCo-authored-by: Sander Muller <github@scode.nl>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.6.1 (#64)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-14T17:00:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3e8be2f9a13dfe5460347a1d157e478a920cd39",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.6.0 (#63)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-14T16:52:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "344342dd545e9041023752650cf734e5d18cc55f",
          "body": "The positional-flag detector resolves a parameter name to report the\nopaque bool/null argument. Parameter names and the variadic flag are\nstatic metadata, independent of the argument types, so the arg-based\nParametersAcceptorSelector::selectFromArgs() — which performs overload\nselection and, for gen\n[…]\nirectly in that case.\n\nAlso replaces the per-call in_array(...) literal in the flag gate with a\nmatch expression, avoiding a 3-element array allocation on every call\nwhose last argument is a constant.",
          "is_bot": false,
          "headline": "perf: avoid arg-based variant selection for single-variant flag checks",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T16:38:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e473a1b11e69d39630375b500232e3505bf9af25",
          "body": "…est (#62)\n\n`$obj?->method(..., true)` (nullsafe calls — common with nullable Laravel\nrelations) were silently skipped by both the flag rule and the manifest\ncollector. Now covered:\n\n- shared instanceCallFlagSite() resolves `$obj->m()` and `$obj?->m()`\n  identically (a nullable receiver collapses vi\n[…]\ne\n  call in both its null and non-null scopes, so the collector fires twice for\n  one site. Errors are auto-deduped by PHPStan; collected data is not, so the\n  writer keys records by their full tuple.",
          "is_bot": false,
          "headline": "feat: cover nullsafe method calls in the positional-flag rule + manif…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T15:24:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6c4d44ef28b5cba27507b359e2136055cd835b36",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.5.0 (#61)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-14T13:37:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cef4ad0a63ae559df4a03ea5f8f2d1ba68ec4411",
          "body": "…pe (#60)\n\nAdds an opt-in producer for hihaho/rector-rules' NamedArgumentFromManifestRector,\nwhich names positional bool/null flags at call sites that only resolve under\nlarastan — the gap bare-PHPStan auto-fixers can't reach. That rector rule is\ninert without a JSON manifest; this produces it.\n\n- D\n[…]\n.\n\nSchema verified against NamedArgumentFromManifestRector 0.9.x: file\n(root-relative), line (call-node start), method (name for calls, FQCN for new),\n0-based argIndex, paramName, value (drift guard).",
          "is_bot": false,
          "headline": "feat: named-argument manifest producer + convention-faithful flag sco…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T13:17:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d1f0129eda09cbff9753fc9a6fd239846bb0d1c4",
          "body": "refactor: consolidate debug-detection wrappers into BaseNoDebugRule",
          "is_bot": false,
          "headline": "Merge pull request #59 from hihaho/refactor/consolidate-debug-wrappers",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T12:11:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "672a01a5b0832ee48855350849e94c9484c2293c",
          "body": "The func/chained/static debug checks were duplicated between each standalone\ndebug rule and its registered Combined* counterpart. Move the three thin\nwrappers into BaseNoDebugRule (funcDebugError, chainedDebugError,\nstaticDebugError), called by both sides, and absorb the static-debug trait\ninto the \n[…]\n last twin/Combined duplication — every check now has a\nsingle shared implementation. No behaviour change: messages, identifiers,\nand gating are unchanged and the full suite passes without test edits.",
          "is_bot": false,
          "headline": "refactor: consolidate debug-detection wrappers into BaseNoDebugRule",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T12:09:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fe98cf072ba096f1edba3e457d27fe15c304c19d",
          "body": "test-registered-combined-rules.md and dedupe-rule-logic-into-traits.md\nshipped in v3.4.1; no-unsafe-request-data.md was implemented in an earlier\nrelease. All tasks complete — removing the finished spec files.",
          "is_bot": false,
          "headline": "chore: remove fully-implemented specs (#58)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T11:17:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b43afe7b9011838b501c92adddde086abfcb980f",
          "body": "The auto-fix PR workflow failed on any PR that produced a working-tree\nchange: it committed composer-install side effects — the environment-specific\n.config/boost/manifest.json regenerated by the post-install boost sync — and\nthen could not push, because checkout runs with persist-credentials: false\n[…]\nmmitted.\n- Restore push credentials only after the PR-controlled rector/pint steps\n  have run, so untrusted code still never executes with a write token in git\n  config while the auto-commit can push.",
          "is_bot": false,
          "headline": "ci: fix auto-fix workflow push auth and over-broad commit scope (#57)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T11:12:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "006da7bda91283079f6c3864bcb3ba0903a2acf6",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.4.1 (#56)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-14T11:05:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "924ca678ac153250e08f20a803f17e2950d0f51f",
          "body": "…aits\n\nrefactor: share rule checks via traits and cover Combined rules",
          "is_bot": false,
          "headline": "Merge pull request #55 from hihaho/refactor/dedupe-rule-logic-into-tr…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T10:57:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cb9959923d45bd8d498d7bf0cc2428333acc8156",
          "body": "Extract the six duplicated rule checks into shared traits so each\nsingle-responsibility twin and its registered Combined* rule call one\nimplementation, removing the drift surface between them:\n\n- DetectsUnsafeRequestData / DetectsUnsafeRequestFacade /\n  DetectsUnsafeRequestHelper, DetectsInvadeUsage\n[…]\nelper calls (e.g. \\REQUEST()) that the twin\nNoUnsafeRequestHelperRule already flagged.\n\nNo behaviour change to the extracted checks; extension.neon and all\npublic constructor signatures are unchanged.",
          "is_bot": false,
          "headline": "refactor: share rule checks via traits and cover Combined rules",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-14T10:46:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "271efb339e17ebe8a2a03700b016e5f9bf5f54a5",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.4.0 (#54)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-13T23:03:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "92b67121077aaad66856477d01229a655b3b32db",
          "body": "Flag a bare true/false/null literal passed positionally as the last argument\nof a first-party method, static, or constructor call. A positional\nsetActive('name', false) hides the flag's meaning; naming it\n(setActive('name', active: false)) makes the call self-documenting.\n\nIdentifier: hihaho.convent\n[…]\nnfigurable via\n  positionalFlagArgument.firstPartyNamespaces)\n\nClassmap the new stub dir and skip it in rector (fixtures must not be\ntransformed — rector strips the empty signature-only stub methods).",
          "is_bot": false,
          "headline": "feat: add positional flag-argument convention rule",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-13T22:10:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c598125d4abcc8ff44e8a37957b7bce86b242b8f",
          "body": "- laravel/pao: agent-optimized output for PHP testing tools\n- nunomaduro/collision: nicer test error reporting\n\nlarastan intentionally omitted — this package analyses with plain PHPStan,\nand larastan auto-registers via extension-installer, which would change its\nown analysis baseline.",
          "is_bot": false,
          "headline": "chore: add canonical dev deps",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-13T18:41:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "05de3aeb307d64fb57c1df97e3bd3d0bab4b411e",
          "body": "- rename workflows to canonical names: tests.yml -> run-tests.yml,\n  analyzer.yml -> phpstan.yml. Workflow `name:` fields (run-tests / PHPStan)\n  and matrix job names are unchanged, so branch-protection check contexts are\n  unaffected; updated self-referencing path filters and README badge URLs.\n- c\n[…]\n phpunit.xml.dist); update the\n  .gitattributes export-ignore entry to match.\n- add a License badge to the README badge row.\n- export-ignore /.config so the boost config stays out of the dist archive.",
          "is_bot": false,
          "headline": "chore: align tooling with canonical repo-init setup",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-13T18:41:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "aeb08ee94407d7b322dbdff42354fe5d306289f7",
          "body": "Laravel 11 is unfixable on CI: CVE-2026-48019 (PKSA-mdq4-51ck-6kdq) flags\nevery laravel/framework v11 release on Packagist with no patched v11, so\nComposer 2.8 advisory-blocking cannot resolve the ^11.31 matrix legs at all.\n\n- illuminate/support: ^12.0||^13.0 (was ^11.31|^12.0|^13.0)\n- orchestra/tes\n[…]\ns: tightening the illuminate/support constraint only\nnarrows install eligibility. Composer keeps Laravel 11 projects on the last\ncompatible release (3.3.0); no consumer build errors. Ships as a minor.",
          "is_bot": false,
          "headline": "chore: drop Laravel 11 support",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-13T18:41:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "08787956a8c7a7f06e2f8563417254fa7550fb3a",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.3.0 (#53)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-13T17:54:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d3a9e1685ad4e9f746619f26c60f794e1d64c3ee",
          "body": "Add post-install-cmd / post-update-cmd autosync hooks and switch sync-ai to\n`boost sync`; refresh the boost manifest. Generated by package-boost-php.",
          "is_bot": false,
          "headline": "chore: sync package-boost tooling",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-13T16:35:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "37d9a28ac53c1bf08c5c7e86dd8e07f75913b8f2",
          "body": "Flag reading a request field inside a FormRequest when the same class's\nrules() never validates it — the inverse of NoUnsafeRequestDataRule, which\nexempts $this reads inside a FormRequest. Identifier:\nhihaho.validation.unvalidatedFormRequestField.\n\nMerged into CombinedMethodCallRule (single-dispatch\n[…]\ne\nhierarchy (a shared base or trait). rules() inherited from a base class is\nfollowed; nested keys match on their root segment. Accessor list is\nconfigurable via unvalidatedFormRequestField.accessors.",
          "is_bot": false,
          "headline": "feat: add UnvalidatedFormRequestFieldRule",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-13T16:35:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dbab322fe50aff71333dcf25fbb231d775689b50",
          "body": "Co-authored-by: SanderMuller <9074391+SanderMuller@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update CHANGELOG for v3.2.0 (#51)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-09T17:26:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c625a78716405a255caef2bf1f05153715b08bb8",
          "body": "…1 advisories are unpatched\n\nAll orchestra/testbench v9.x versions require laravel/framework ^11.x, which is\ncurrently blocked by Packagist security advisories on every v11 release through\nv11.54. The advisories are external (appeared after the 2026-05-24 green run)\nand unrelated to this package. Add continue-on-error scoped to the L^11.31 legs\nso CI stays green until Laravel ships a patched v11 release.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): allow L^11.31 matrix legs to fail while laravel/framework v1…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-09T07:09:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a856f602b4b47c2648e93d867aad3bc5b7f19bae",
          "body": "…ation guideline\n\nReplace sandermuller/package-boost with sandermuller/package-boost-php ^1.0\nand sandermuller/boost-skills ^2.4. Move boost config to .config/boost.php\n(supported by boost-core 1.1.1+). Remove all local .ai/skills/ — canonical\nequivalents now come from vendor; phpstan-developer sour\n[…]\nitting directly to main, and the benchmark-table workflow does\nnot exist. Gitignore generated boost outputs (.boost/, .claude/skills/, etc.).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: migrate to package-boost-php + boost-skills, fix release-autom…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-09T07:02:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8d9b4913924116dd9bb292114f4d6d0b573e8f59",
          "body": "… from base constants\n\nMove isDebugHelperMethodCall to BaseNoDebugRule so ChainedNoDebugInNamespaceRule\nand CombinedMethodCallRule share a single implementation. Promote\nFUNCTION_DEBUG_STATEMENTS and METHOD_DEBUG_STATEMENTS to protected so Combined\nrules can derive their quick-reject lookups from the authoritative source instead\nof duplicating the set.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: deduplicate isDebugHelperMethodCall and derive quick-reject…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-09T07:02:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1a70d6dd4fb984622386e296267b391db46c46b8",
          "body": "Rector FlipTypeControlToUseExclusiveTypeRector: replace !== null\nguards with instanceof IdentifierRuleError for explicit typing, and\nstrip redundant readonly keyword on non-promoted properties inside\nfinal readonly classes. Pint fixes spacing in three files.\n\nAlso updates autoresearch/phpstan-rules-progress.md with final results:\noverhead now ≈ 0ms (within ±150ms noise floor of a ~12s benchmark).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "autoresearch: apply Rector + Pint cleanups, update progress log",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:56:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fab06174e7a9bb7e97b265549c89b2b6dc8aa0bd",
          "body": "Adds INTERESTING_FUNC_NAMES const array containing the names of all\nfunctions this rule cares about. Calls whose name is not in the set\nand contains no backslash return [] immediately, skipping all three\nsub-rule checks. Qualified function names (containing backslash) bypass\nthe filter so that edge-cases like qualified request() helpers are still\ncaught via getLast() in checkRequestHelper.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "autoresearch: add quick-reject const lookup in CombinedFuncCallRule",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:52:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e883fc9e889874bce339ee517a1e8ba6bb6795c6",
          "body": "Precompute a merged lookup of debug method names + unsafe request method\nnames (both lowercased). A single isset in processNode short-circuits\nthe two sub-rule checks for the ~99% of method calls that are neither\ndebug-related nor unsafe request accessors, avoiding the strtolower +\nmethod dispatch overhead for every non-interesting method call.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "autoresearch: add quick-reject lookup in CombinedMethodCallRule",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:49:58Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6ea2c19e842a534b380a66a3d5729c55561a37bc",
          "body": "Raise cognitive_complexity.class from 12→35 (combined rules merging 3\nsub-rules are intentionally more complex by design), extract processNode\nlogic into private methods to keep each function under 10, add\nmatchDebugNamespace helper to BaseNoDebugRule shared by all debug rules,\nfix property.notFound\n[…]\nto accept Name\ninstead of StaticCall, add @extends generics PHPDoc to combined rules,\nand add @var annotation to static classIsRequest cache.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "autoresearch: fix all 25 phpstan errors in combined rules",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:44:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fd41f129f2d58bcb2b709d936ec437bdefb69dbb",
          "body": "… to eliminate 1/2 dispatch overhead",
          "is_bot": false,
          "headline": "autoresearch: OOB3 merge MethodCall rules into CombinedMethodCallRule…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:23:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d8df31735d2f15d8c65a5ca737a7ec8504a085b7",
          "body": "…eliminate 2/3 dispatch overhead",
          "is_bot": false,
          "headline": "autoresearch: OOB1 merge FuncCall rules into CombinedFuncCallRule to …",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:22:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6a86c20972231b7b9aad4c9ad65140595feb995d",
          "body": "… to eliminate 2/3 dispatch overhead",
          "is_bot": false,
          "headline": "autoresearch: OOB2 merge StaticCall rules into CombinedStaticCallRule…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:18:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a2f824e76272826d548641d3ba6ef1b9afc340de",
          "body": "…), str_contains for multi-part check",
          "is_bot": false,
          "headline": "autoresearch: OOB4+B9 use ->name direct property instead of toString(…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c11f1893dde4c36eeab05091cfa63136cb8e3195",
          "body": "…e to skip strtolower for non-Request calls",
          "is_bot": false,
          "headline": "autoresearch: B8 add getLast() pre-filter in NoUnsafeRequestFacadeRul…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:02:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0c51a1b55ceb73c62036c5c3aadddfde041f8b22",
          "body": "…n ChecksNamespace",
          "is_bot": false,
          "headline": "autoresearch: B6 get namespace once per namespaceStartsWithAny call i…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:01:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5fb7c122ab4c0c0cfff6c314328ab404890804ac",
          "body": "…questDataRule",
          "is_bot": false,
          "headline": "autoresearch: B5 cache ObjectType result per class name in NoUnsafeRe…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T22:00:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90fe9934e424822cdbed11ce521f12c93ee28885",
          "body": "…gInNamespaceRule constructor",
          "is_bot": false,
          "headline": "autoresearch: B4 cache Facade class reflection in StaticChainedNoDebu…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T21:59:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "79fbb3b14ed2d960108c61b0c6d4aed163008cdf",
          "body": "… in NoUnsafeRequestHelperRule",
          "is_bot": false,
          "headline": "autoresearch: B2 move namespace check before ReflectionProvider calls…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T21:57:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c3a4984b37f6ec67e475deb9e2c1325db3210af",
          "body": "…edNoDebugInNamespaceRule",
          "is_bot": false,
          "headline": "autoresearch: B1 move namespace check before type resolution in Chain…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T21:57:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "082b15fb5745fbcb7f8224bc7d62686a74aaf7c7",
          "body": "…cChainedNoDebugInNamespaceRule",
          "is_bot": false,
          "headline": "autoresearch: B1 move namespace check before type resolution in Stati…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T21:56:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9ab35987cb11dd31e8d0e320f654e1516a9b54a7",
          "body": null,
          "is_bot": false,
          "headline": "autoresearch: B3 replace in_array with isset hash map in BaseNoDebugRule",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T21:54:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1961c55272c0bc919f678a6e8a828def68c2a4d5",
          "body": "…liasInBlade",
          "is_bot": false,
          "headline": "autoresearch: B7 add static ReflectionClass cache in OnlyAllowFacadeA…",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-06-08T21:50:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9cb0dfd945f58ee217c4cb4ff1df4029c33c8df7",
          "body": "Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.37.0 to 2.37.1.\n- [Release notes](https://github.com/shivammathur/setup-php/releases)\n- [Commits](https://github.com/shivammathur/setup-php/compare/accd6127cb78bee3e8082180cb391013d204ef9f...7c071dfe9dc99bdf297fa79cb49e\n[…]\nirect:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump shivammathur/setup-php from 2.37.0 to 2.37.1 (#50)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-05-24T12:42:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "280f0d8e24bfd68daffdb044f1003029e3e429fe",
          "body": "Updates the requirements on [sandermuller/package-boost](https://github.com/sandermuller/package-boost) to permit the latest version.\n- [Release notes](https://github.com/sandermuller/package-boost/releases)\n- [Changelog](https://github.com/SanderMuller/package-boost/blob/main/CHANGELOG.md)\n- [Commi\n[…]\ndency-version: 0.15.0\n  dependency-type: direct:development\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update sandermuller/package-boost requirement from ^0.11 to ^0.15 (#49)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-05-14T09:09:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f93af97626327af9774706a9bc25db46d00bf79c",
          "body": "Updates the requirements on [sandermuller/package-boost](https://github.com/sandermuller/package-boost) to permit the latest version.\n- [Release notes](https://github.com/sandermuller/package-boost/releases)\n- [Changelog](https://github.com/SanderMuller/package-boost/blob/main/CHANGELOG.md)\n- [Commi\n[…]\ndency-version: 0.11.0\n  dependency-type: direct:development\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Update sandermuller/package-boost requirement from ^0.9 to ^0.11 (#48)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-05-07T08:07:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "07e0f29ef00923608dd28134323b52b15a6512e8",
          "body": "Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7.0.8 to 8.1.1.\n- [Release notes](https://github.com/peter-evans/create-pull-request/releases)\n- [Commits](https://github.com/peter-evans/create-pull-request/compare/271a8d0340265f705b14b6d32b9829c1cb33d\n[…]\nirect:production\n  update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump peter-evans/create-pull-request from 7.0.8 to 8.1.1 (#47)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-04-23T12:47:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5696ddfd7fa16a6f3016742a4e0ec778f72b7057",
          "body": "Backfill entries that the Update Changelog workflow should have\ncommitted on each release but couldn't (broken create-pull-request\nSHA for v3.1.1; Duplicate Authorization header for v3.1.2). Content\nis the release body verbatim for each tag.",
          "is_bot": false,
          "headline": "Update CHANGELOG for v3.1.1 and v3.1.2 (#46)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-22T14:59:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "42d2e9e60c0a3effaefaab0e77fad0c23f01199a",
          "body": "actions/checkout persists its token as an Authorization header by\ndefault; peter-evans/create-pull-request then adds its own token,\nproducing a Duplicate header: Authorization and failing with\ngit exit code 128. Disabling credential persistence on checkout\nlets create-pull-request own the remote-auth entirely.",
          "is_bot": false,
          "headline": "fix: disable persist-credentials on checkout in update-changelog",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-22T14:53:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0bda21fbca9954cf7cd68a2e9d4853005bf81912",
          "body": "actions/checkout persists its token as an Authorization header by\ndefault; peter-evans/create-pull-request then adds its own token,\nproducing a Duplicate header: Authorization and failing with\ngit exit code 128. Disabling credential persistence on checkout\nlets create-pull-request own the remote-auth entirely.",
          "is_bot": false,
          "headline": "fix: disable persist-credentials on checkout in update-changelog",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-22T14:52:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4d47ab987fafe06dd63126f5cbfadc77e1cc1c7e",
          "body": "Prior pin referenced a SHA that does not exist in the action repo\n(typo in the second half of the hash), which broke the Update\nChangelog workflow on the v3.1.1 release.",
          "is_bot": false,
          "headline": "fix: correct pinned SHA for peter-evans/create-pull-request@v7.0.8",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-22T14:48:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c681f4705795fa3e2dcb8720127e2f6617ccea53",
          "body": "Each rule processes every FuncCall / MethodCall / StaticCall PHPStan\nvisits, so the filters before the \"real\" check fire on the order of\n10^4 times for a medium codebase. Small constant-factor cleanups here:\n\n- NoUnsafeRequestHelperRule: short-name prefilter (`strtolower(getLast())\n  !== 'request'`)\n[…]\ny checks share one build.\n\nNo behavioural change. All five rules remain `final readonly class`;\nno public API surface touched. `.gitignore` ignores the `/autoresearch/`\nbenchmarking scratch directory.",
          "is_bot": false,
          "headline": "perf: reduce per-node work in request-rule hot paths",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-22T14:40:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0dac2572da59a784f1d6d88d2854014f7a18dab3",
          "body": null,
          "is_bot": false,
          "headline": "Update README.md",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T18:53:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b9eee99cfebc85c5cd14e6b6b59dc87da76bcf7f",
          "body": "Three individual rule subsections collapse into one Request-validation\ngroup with a summary table, one shared code example, and two\nsubsections (Configuration, Adopting on an existing codebase). Net\nsize drop roughly 230 -> 140 lines while keeping all identifiers,\nexemption rules, defaults, and fiel\n[…]\nt unreliability),\ncollectiq (InputBag escape hatch, dead-code surfacing), and hihaho\n(FormRequest-wrong-key mental model trap, validated()-strips-nested)\nfield reports from the v3.1.0 adoption passes.",
          "is_bot": false,
          "headline": "Restructure Request-rules section, humanize adoption prose",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T18:51:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ab78fa06bc36809412d9559e300a073f01961313",
          "body": "* Fix update-changelog workflow + backfill v3.1.0 entry\n\nThe `Update Changelog` workflow failed on the v3.1.0 release because\n`stefanzweifel/git-auto-commit-action` pushes directly to `main`, which\nis a protected branch requiring PRs (GH006: Protected branch update\nfailed).\n\nSwitching to `peter-evan\n[…]\n\n\n* Update .github/workflows/update-changelog.yml\n\nCo-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>\n\n---------\n\nCo-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix update-changelog workflow + backfill v3.1.0 entry (#45)",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T18:43:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d44908374e09067f79f1687e1d5ae11e6afb8e82",
          "body": null,
          "is_bot": false,
          "headline": "Draft v3.1.0 release notes",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T16:33:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e9d92adbb03ca107f29d060cf786d6f98a399837",
          "body": null,
          "is_bot": false,
          "headline": "Update UPGRADING.md",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T16:30:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5fe2237a4d503c03fd6db0d49b319d4bf71f6fe0",
          "body": null,
          "is_bot": false,
          "headline": "sync-ai",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T16:29:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fe3434fde806d5a8ab27a3a45a8b6229f2602f7e",
          "body": "Data rule tip now explicitly names $request->safe()->string('key') as\nthe ergonomic migration path for $request->string() — ValidatedInput\nhas matching typed accessors, so the Stringable/int/bool chaining\npattern survives the move to validated data. Collectiq dogfood\nsurfaced 4 such cases where the \n[…]\naveat: those architectures push input handling through component\nproperties and form schemas — outside the rule's Request-method\ntargets. A low hit count there is structural, not proof of\ncleanliness.",
          "is_bot": false,
          "headline": "Sharpen tip messages, document Livewire/Filament caveat",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T16:15:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bd2f17fa7ac129bbe78a5b4cd6d5cca958bb620a",
          "body": "File uploads are the highest-consequence unvalidated-input surface\n(size, mime, content). hihaho dogfood surfaced a live case reading\nplayer-uploaded attachments via Request::file() with zero flags\nbecause file readers were missing from the default list. Added\nfile and allFiles to extension.neon def\n[…]\nck types. The existing rule\ndesign relied on it implicitly (and hihaho has real fixtures using\ntoArray(mixed \\$request) with docblock @param Illuminate\\Http\\Request),\nbut it was not explicitly tested.",
          "is_bot": false,
          "headline": "Add file/allFiles to unsafeMethods defaults, test docblock receiver",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T15:57:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "354f61f0bc960109d3a8ced9341b25f60379fd3c",
          "body": null,
          "is_bot": false,
          "headline": "composer qa",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T15:54:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "82a88ac9dd9ed98ddc43e83179f1f0491065a8ce",
          "body": "Fortify / auth response classes implement contract-dictated signatures\nlike LoginResponse::toResponse(Request $request). Signature is fixed by\nthe interface, same structural reason as App\\\\Providers — no validation\nboundary inside the class. Defaulting matches that contract pattern.\n\nApp\\\\Http\\\\Resources stays opt-in: whether a JsonResource should read\nraw request at all is a legitimate architectural debate, not a\nframework-forced pattern.",
          "is_bot": false,
          "headline": "Default-exclude App\\\\Http\\\\Responses",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T14:30:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "db32fad711564578ff0eeb7db33a988dbc913e96",
          "body": "NoUnsafeRequestHelperRule now interpolates the literal string argument\ninto the error message (request('key')) when available, falling back to\nrequest(...) for dynamic keys. Makes triage grep-friendly when a\ncodebase has many helper-form hits.\n\nREADME \"Expected baseline categories\" section gets an inline\n@phpstan-ignore example for the dynamic-key admin CRUD pattern, so\nconsumers have a clear alternative to baseline-file suppression.",
          "is_bot": false,
          "headline": "Sharpen helper-rule message + document inline ignore pattern",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T14:24:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "120da0078e8566335d73c4529663c56d107d21dd",
          "body": "Framework bootstrap code (RateLimiter::for throttle closures, Fortify\nresponse bindings, service provider setup) receives the raw Request by\nLaravel design and has no FormRequest entry point. Excluding\nApp\\\\Providers by default removes that noise while leaving all three\nrules opt-inable for project-specific framework-adapter layers.\n\nChecksNamespace gains a namespaceStartsWithAny() helper shared by all\nthree rules to keep per-rule cognitive complexity under the package cap.",
          "is_bot": false,
          "headline": "Add excludeNamespaces config, default App\\\\Providers",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T13:55:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "071ba1db3e1f315f7a821ddb49a6d69e6484cf5e",
          "body": "Per mijntp dogfood pass: codebases will legitimately baseline admin\ndynamic-key CRUD, pre-validation RateLimiter closures, Fortify response\ncontracts, and JsonResource::toArray. Call these out explicitly as\nexpected territory rather than rule bugs.\n\nAlso clarify that the scope-class exemption uses PHPStan inheritance\nresolution, so custom base FormRequest classes work transparently.",
          "is_bot": false,
          "headline": "Document expected-baseline categories",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T13:42:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cbb97ed6409a1ce582c00ac45b7029122c3f5f74",
          "body": "Three rules preventing unvalidated reads from Illuminate\\Http\\Request\nin application code. Use-validated-data-only is enforced at MethodCall\non Request/FormRequest receivers, FuncCall on request('key') direct-arg\nhelper, and StaticCall on the Illuminate\\Support\\Facades\\Request facade.\n\nRaw reads ins\n[…]\n— that is where validation sources its data.\n\nConfig: noUnsafeRequestData.{unsafeMethods, namespaces}. Identifiers:\nhihaho.validation.noUnsafeRequestData, noUnsafeRequestHelper,\nnoUnsafeRequestFacade.",
          "is_bot": false,
          "headline": "Add NoUnsafeRequestData / Helper / Facade rules",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T13:26:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ff3a883ba0168deda6c8f4d107f1a13292605f25",
          "body": null,
          "is_bot": false,
          "headline": "Update composer.json",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T11:08:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b8f00aa94765f06255d337118ffe117e79599409",
          "body": null,
          "is_bot": false,
          "headline": "Update .gitignore",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T11:08:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f6f4195da993c5c90dd5094e1d47003abf206de8",
          "body": null,
          "is_bot": false,
          "headline": "Update composer.json",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T08:28:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3d626e99d0b5f93bf727aa2f91d9718b18275ec0",
          "body": null,
          "is_bot": false,
          "headline": "Update composer.json",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-21T08:28:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "48aa577e97622c7e194eef504589c3db2a12f6b5",
          "body": null,
          "is_bot": false,
          "headline": "Update README.md",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-19T12:47:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc217dd944f1b35d07db3c8a024599a6c143847d",
          "body": null,
          "is_bot": false,
          "headline": "Update README.md",
          "author_name": "Sander Muller",
          "author_login": "SanderMuller",
          "committed_at": "2026-04-12T16:35:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 31,
      "commits_last_year": 106,
      "latest_release_at": "2026-07-07T15:53:26Z",
      "latest_release_tag": "v3.14.0",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 15,
      "days_since_latest_release": 20,
      "mean_days_between_releases": 2.3
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 50,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "hihaho/phpstan-rules",
          "exists": true,
          "license": "MIT",
          "keywords": [],
          "ecosystem": "packagist",
          "matches_repo": true,
          "registry_url": "https://packagist.org/packages/hihaho/phpstan-rules",
          "is_deprecated": false,
          "latest_version": "v3.14.0",
          "repository_url": "https://github.com/hihaho/phpstan-rules",
          "versions_count": 31,
          "total_downloads": 52119,
          "dependents_count": 1,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 5296,
          "first_published_at": null,
          "latest_published_at": "2026-07-07T12:08:10Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 21
        }
      ]
    },
    "popularity": {
      "forks": 1,
      "stars": 7,
      "watchers": 5,
      "fork_history": {
        "days": [
          {
            "date": "2024-10-30",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 1,
        "total_forks": 1
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": true,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 17604,
      "source_files_sampled": 193,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        ".github/copilot-instructions.md",
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 12530
    },
    "dependencies": {
      "manifests": [
        "composer.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": 25,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "packagist"
      ],
      "dependencies": [
        {
          "name": "illuminate/database",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "^12.0||^13.0"
        },
        {
          "name": "illuminate/http",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "^12.0||^13.0"
        },
        {
          "name": "illuminate/support",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "^12.0||^13.0"
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "illuminate/database",
            "direct": true,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "illuminate/http",
            "direct": true,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "illuminate/support",
            "direct": true,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "larastan/larastan",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "laravel/pao",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "laravel/pint",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "nikic/php-parser",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "nunomaduro/collision",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "orchestra/testbench",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "php",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpstan/extension-installer",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpstan/phpstan",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpstan/phpstan-deprecation-rules",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpstan/phpstan-phpunit",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpstan/phpstan-strict-rules",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpunit/phpunit",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "rector/rector",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "rector/type-perfect",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "sandermuller/boost-skills",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "sandermuller/package-boost-php",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "spatie/invade",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "spaze/phpstan-disallowed-calls",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "symplify/phpstan-extensions",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "tomasvotruba/cognitive-complexity",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "tomasvotruba/type-coverage",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 25,
        "direct_count": 3,
        "indirect_count": 22
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 83,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 5
      },
      "bus_factor": 1,
      "bot_contributors": 2,
      "top_contributors": [
        {
          "type": "User",
          "login": "SanderMuller",
          "commits": 109,
          "avatar_url": "https://avatars.githubusercontent.com/u/9074391?v=4"
        },
        {
          "type": "User",
          "login": "RobertBoes",
          "commits": 32,
          "avatar_url": "https://avatars.githubusercontent.com/u/2871897?v=4"
        },
        {
          "type": "User",
          "login": "Treggats",
          "commits": 21,
          "avatar_url": "https://avatars.githubusercontent.com/u/27585?v=4"
        }
      ],
      "contributors_sampled": 3,
      "top_contributor_share": 0.673
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "auto-fix.yml",
        "phpstan.yml",
        "run-tests.yml",
        "update-changelog.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": true,
      "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": 6,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "25 out of 25 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/15 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 4 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 10,
            "reason": "SAST tool is run on all commits",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": null,
            "reason": "No tokens found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "4fafc86cb9e719d86102a0c9504ec09351481e55",
        "ran_at": "2026-07-28T15:06:32Z",
        "aggregate_score": 6.7,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-28T13:03:02Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-07T21:44:02Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/hihaho/phpstan-rules",
    "host": "github.com",
    "name": "phpstan-rules",
    "owner": "hihaho"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 65,
      "inputs": {
        "security": 67,
        "vitality": 84,
        "community": 44,
        "governance": 60,
        "engineering": 66
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 84,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 74,
            "inputs": {
              "commits_last_year": 106,
              "human_commit_share": 0.75,
              "days_since_last_push": 0,
              "active_weeks_last_year": 15
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "15/52 weeks with commits",
                "points": 10.4,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 15
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "106 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 106
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "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": 31,
              "latest_release_tag": "v3.14.0",
              "releases_from_tags": false,
              "days_since_latest_release": 20,
              "mean_days_between_releases": 2.3
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "31 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 31
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 20 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 20
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~2.3 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 2.3
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 0,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 0 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 44,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 16,
            "inputs": {
              "forks": 1,
              "stars": 7,
              "watchers": 5,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "7 stars",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "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": "5 watchers",
                "points": 3.3,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "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": null,
            "notes": [],
            "value": 52,
            "inputs": {
              "packages": [
                "hihaho/phpstan-rules"
              ],
              "dependents": 1,
              "ecosystems": "packagist",
              "total_downloads": 52119,
              "monthly_downloads": 5296
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "5,296 downloads/month across packagist",
                "points": 49.7,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 5296,
                      "ecosystems": "packagist"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "1 packages depend on it",
                "points": 2,
                "status": "partial",
                "details": [
                  {
                    "code": "registry_dependents",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "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": 60,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "at_risk",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 30,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 3,
              "top_contributor_share": 0.673
            },
            "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 67% of commits",
                "points": 7.4,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 67
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "3 contributors",
                "points": 4.1,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 4 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 68,
            "inputs": {
              "merged_prs": 83,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 5
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "83/88 decided PRs merged",
                "points": 36.1,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 83,
                      "decided": 88
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/15 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "followers": 5,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "hihaho",
              "public_repos": 9,
              "account_age_days": 3245
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "5 followers of hihaho",
                "points": 5.6,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 5,
                      "login": "hihaho"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "9 public repos, account ~8 yr old",
                "points": 19.3,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 9
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 8
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "hihaho/phpstan-rules"
              ],
              "ecosystems": "packagist",
              "any_deprecated": false,
              "min_days_since_publish": 21
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on packagist",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "packagist"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 21 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 21
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "31 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 31
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 66,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 74,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": true,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "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": 6.4,
                "status": "met",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "25 out of 25 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": "https://guidelines.hihaho.com",
              "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://guidelines.hihaho.com",
                "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 67,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 67,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 13,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 5,
              "scorecard_aggregate": 6.7
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 4.5,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "25 out of 25 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/15 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 4 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is run on all commits",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 7
            },
            "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": 54,
        "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.853,
              "agent_instruction_files": [
                ".github/copilot-instructions.md",
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 12530
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": ".github/copilot-instructions.md, AGENTS.md, CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".github/copilot-instructions.md, AGENTS.md, CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "64 of 75 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 64,
                      "sampled": 75
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 44,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.09,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0.08
            },
            "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "9 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 9,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "8 of the last 100 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 8,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "primary_language": "PHP",
              "largest_source_bytes": 17604,
              "source_files_sampled": 193,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "PHP without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "PHP"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/193 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 193,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "critical",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "example_dirs": [],
              "has_mcp_signal": true,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              }
            ]
          }
        ],
        "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-28T15:06:50.497816Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/h/hihaho/phpstan-rules.svg",
  "full_name": "hihaho/phpstan-rules",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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