公开记录
软件健康报告模式 0.27.0 · 指标 2.5.0 · 2026-07-30 22:50 UTC

TYPO3 / Fluid

Fluid template rendering engine - Standalone version

PHPLGPL-3.0★ 169 星标⑂ 107 复刻始于 2015年8月在 GitHub 上查看 ↗
类型如何判定

TYPO3/Fluid 的健康指数为 100 分中的 80 分,处于「优秀」区间。 其得分最高的类别是Engineering Quality(80/100),最低的是AI Readiness(41/100)。 最近一次更新在 46 天前。 近期的大部分工作由 3 位贡献者完成。

80
总分 / 100
优秀

软件健康指数

指标归入加权类别,统一采用 1–100 量表。总体分先取类别加权平均,再依据公开记录的分布进行校准,使各等级具有百分位含义;当公开证据触发高风险司法辖区政策时,评级会按政策调整,并设置 34(存在风险)的上限。

80
卓越93-100公开记录中的最高层级(约前 5%);基本满足所有检验标准
优秀80-92各方面均表现强劲;仅有少量不足
良好65-79健康;不足之处有限且可控
中等50-64可接受,但存在明显不足;建议进行审查
薄弱35-49多个领域存在实质性薄弱环节
存在风险20-34存在重大薄弱环节;采用时应保持审慎
危急1-19问题严重(项目被弃置、仅有单一维护者、缺乏基本工程规范)
活力社区与采用可持续性与治理工程质量安全AI 就绪度

评分画像

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

加权总体分 68 经校准后在公布的指数量表上为 80(记录校准 2026-08-02)。

所有权

117 关注者23 个公开仓库始于 2009年5月

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布
Packagisttypo3fluid/fluid5.3.1401,469117105 天前

按类别列示的指标

活力

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

69良好 · 占总体的 21%
评分方式
18/36推送新近度 — 最近一次推送于 46 天前
18/36提交节奏 — 52 周中有 26 周有提交
18/18提交量 — 最近一年 126 次提交
1/10OpenSSF Scorecard:Maintained — 2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1
所用输入
commits_last_year126
human_commit_share1
days_since_last_push46
active_weeks_last_year26

发布纪律

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

社区与采用

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

70良好 · 占总体的 17%
评分方式
36.1/60星标 — 169 个星标
16.9/25复刻 — 107 个复刻
7.4/15关注者 — 22 位关注者
所用输入
forks107
stars169
watchers22
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

70良好
评分方式
22.5/22.5README
22.5/22.5许可证 — 可识别的许可证(LGPL-3.0)
18/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
readme_badges
has_contributing
has_issue_template
has_code_of_conduct
readme_badge_services
has_pull_request_template
评分方式
74.7/80月度下载量 — packagist 合计每月 401,469 次下载
13.1/20注册表被依赖数 — 90 个软件包依赖它
所用输入
packagestypo3fluid/fluid
dependents90
ecosystemspackagist
total_downloads16,388,135
monthly_downloads401,469

可持续性与治理

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

79良好 · 占总体的 23%
评分方式
36/54巴士系数 — 3 位贡献者贡献了半数提交
17.8/22.5提交分布 — 头号贡献者编写了 21% 的提交
13.5/13.5贡献者广度 — 100 位贡献者
10/10OpenSSF Scorecard:Contributors — project has 37 contributing companies or organizations
所用输入
bus_factor3
contributors_sampled100
top_contributor_share0.211
评分方式
34.4/42议题解决 — 82% 的议题已关闭
26.5/30PR 接受 — 已裁定的 PR 中 924/1,046 已合并
0/13Newcomer PR acceptance — 30 天内没有首次贡献者的 PR 得到裁决
6/15OpenSSF Scorecard:Code-Review — Found 14/30 approved changesets -- score normalized to 4
所用输入
merged_prs924
open_issues59
closed_issues265
prs_merged_7d
prs_decided_7d
prs_merged_30d
prs_decided_30d
issue_closed_ratio0.818
closed_unmerged_prs122
first_time_authors_30d
first_time_prs_merged_30d
first_time_prs_decided_30d
已排除计分(无数据或不适用):newcomer_pr_acceptance。 其余权重已重新归一化。
评分方式
30/30所有权背书 — 组织持有
0/20已验证域名
14.9/25所有者影响力 — TYPO3 有 117 位关注者
22.1/25既往记录 — 23 个公开仓库,账户约 17 年
所用输入
followers117
owner_typeOrganization
is_verified
owner_loginTYPO3
public_repos23
account_age_days6,274
评分方式
25/25已发布且可解析 — packagist 上有 1 个软件包
35/35发布时效 — 最近一次发布于 105 天前
20/20版本历史 — 117 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagestypo3fluid/fluid
ecosystemspackagist
any_deprecated
min_days_since_publish105

工程质量

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

80优秀 · 占总体的 19%

工程实践

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

文档

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

安全

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

42薄弱 · 占总体的 16%

安全态势

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

AI 就绪度

该仓库在多大程度上具备与 AI 编码代理协同开发与维护的条件?权重刻意设小(4%):代理工具链是一项真实的维护信号,但完全不具备的仓库仍可达到 100/100。

41薄弱 · 占总体的 4%
评分方式
0/45代理指令 — 没有 CLAUDE.md / AGENTS.md / 编辑器规则
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 98 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.98
agent_instruction_files
agent_instruction_max_bytes
评分方式
0/18一条命令的引导启动
22/22自动化测试
11/11Lint / 格式化配置 — .php-cs-fixer.dist.php
0/11静态类型检查
0/10可复现环境
0/10已体现的代理实践 — 最近 100 次提交中没有代理编写的提交
0/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
toolchain_manifests
dependency_bot_commit_share0
已排除计分(无数据或不适用):OpenSSF Scorecard:Pinned-Dependencies。 其余权重已重新归一化。
评分方式
0/45可类型检查的代码 — PHP,未配置类型检查
55/55可控的文件大小 — 采样的 381 个源文件中有 0 个超过 60KB
所用输入
primary_languagePHP
largest_source_bytes42,311
source_files_sampled381
oversized_source_files0
评分方式
0/40API 模式(OpenAPI/GraphQL/proto)
0/20MCP 服务器
40/40可运行示例 — examples
所用输入
example_dirsexamples
has_mcp_signal
api_schema_files

关键数据

169GitHub 星标
100贡献者
126最近 12 个月提交数
46距最近推送天数
38发布版本数
3巴士系数(bus factor)
59开放议题
Packagist软件包生态系统数

数据采集警告

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

更多细节

Star 与 Fork 历史 0 ★ / 107 ⇿
0Star
107Fork
38发布

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

02040608010012010752015-092021-012026-04
主版本 2次版本 16修订 20

每个点涵盖 10 天。

OpenSSF Scorecard 4.2 / 10
4.2综合

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

10Binary-Artifactsno binaries found in the repo
不适用Branch-Protectioninternal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
10CI-Tests30 out of 30 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
4Code-ReviewFound 14/30 approved changesets -- score normalized to 4
10Contributorsproject has 37 contributing companies or organizations
不适用Dangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
1Maintained2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1
不适用Packagingpackaging workflow not detected
不适用Pinned-Dependenciesno dependencies found
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
不适用Token-PermissionsNo tokens found
10Vulnerabilities0 existing vulnerabilities detected
全部依赖 11

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

注册表软件包版本关系
Packagistext-json间接
Packagistext-mbstring间接
Packagistext-simplexml间接
Packagistfriendsofphp/php-cs-fixer间接
Packagistinfection/infection间接
Packagistphp间接
Packagistphpstan/phpstan间接
Packagistphpstan/phpstan-phpunit间接
Packagistphpunit/phpunit间接
Packagistpsr/container间接
Packagistt3docs/fluid-documentation-generator间接
依赖安全公告 未评估

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 6563,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "PHP": 1428096,
        "HTML": 7971
      },
      "pushed_at": "2026-06-14T12:03:59Z",
      "created_at": "2015-08-13T15:04:55Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-05T12:05:10Z",
      "description": "Fluid template rendering engine - Standalone version",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "LGPL-3.0",
      "default_branch": "main",
      "license_spdx_raw": "LGPL-3.0",
      "primary_language": "PHP",
      "significant_languages": [
        "PHP"
      ]
    },
    "owner": {
      "blog": "https://typo3.org",
      "name": "TYPO3 GitHub Department",
      "type": "Organization",
      "login": "TYPO3",
      "company": null,
      "location": null,
      "followers": 117,
      "avatar_url": "https://avatars.githubusercontent.com/u/88698?v=4",
      "created_at": "2009-05-26T11:58:25Z",
      "is_verified": null,
      "public_repos": 23,
      "account_age_days": 6274
    },
    "license": {
      "state": "standard",
      "spdx_id": "LGPL-3.0",
      "raw_spdx": "LGPL-3.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "4.6.1",
          "kind": "patch",
          "published_at": "2026-04-16T17:27:38Z"
        },
        {
          "tag": "5.3.1",
          "kind": "patch",
          "published_at": "2026-04-16T17:29:34Z"
        },
        {
          "tag": "5.3.0",
          "kind": "minor",
          "published_at": "2026-04-07T18:05:17Z"
        },
        {
          "tag": "4.6.0",
          "kind": "minor",
          "published_at": "2026-03-13T10:32:00Z"
        },
        {
          "tag": "5.2.0",
          "kind": "minor",
          "published_at": "2026-03-11T11:57:45Z"
        },
        {
          "tag": "5.1.1",
          "kind": "patch",
          "published_at": "2026-02-20T13:39:41Z"
        },
        {
          "tag": "5.1.0",
          "kind": "minor",
          "published_at": "2026-02-02T18:27:25Z"
        },
        {
          "tag": "4.5.1",
          "kind": "patch",
          "published_at": "2026-02-04T19:15:03Z"
        },
        {
          "tag": "5.0.3",
          "kind": "patch",
          "published_at": "2025-12-17T14:29:11Z"
        },
        {
          "tag": "5.0.2",
          "kind": "patch",
          "published_at": "2025-11-24T09:29:12Z"
        },
        {
          "tag": "5.0.1",
          "kind": "patch",
          "published_at": "2025-11-18T13:42:50Z"
        },
        {
          "tag": "5.0.0",
          "kind": "major",
          "published_at": "2025-11-16T15:57:27Z"
        },
        {
          "tag": "4.5.0",
          "kind": "minor",
          "published_at": "2025-11-15T14:38:21Z"
        },
        {
          "tag": "4.4.3",
          "kind": "patch",
          "published_at": "2025-08-28T12:05:37Z"
        },
        {
          "tag": "4.4.2",
          "kind": "patch",
          "published_at": "2025-08-06T10:18:04Z"
        },
        {
          "tag": "4.4.1",
          "kind": "patch",
          "published_at": "2025-08-06T10:12:06Z"
        },
        {
          "tag": "4.4.0",
          "kind": "minor",
          "published_at": "2025-07-28T15:14:24Z"
        },
        {
          "tag": "4.3.0",
          "kind": "minor",
          "published_at": "2025-06-24T13:09:34Z"
        },
        {
          "tag": "4.2.0",
          "kind": "minor",
          "published_at": "2025-05-19T11:26:58Z"
        },
        {
          "tag": "4.1.2",
          "kind": "patch",
          "published_at": "2025-04-22T08:33:53Z"
        },
        {
          "tag": "4.1.1",
          "kind": "patch",
          "published_at": "2025-04-17T15:52:16Z"
        },
        {
          "tag": "4.1.0",
          "kind": "minor",
          "published_at": "2025-04-09T16:35:12Z"
        },
        {
          "tag": "4.0.3",
          "kind": "patch",
          "published_at": "2025-01-21T10:02:22Z"
        },
        {
          "tag": "4.0.2",
          "kind": "patch",
          "published_at": "2024-11-18T21:58:55Z"
        },
        {
          "tag": "4.0.1",
          "kind": "patch",
          "published_at": "2024-10-03T09:54:14Z"
        },
        {
          "tag": "4.0.0",
          "kind": "major",
          "published_at": "2024-09-11T08:50:15Z"
        },
        {
          "tag": "2.15.0",
          "kind": "minor",
          "published_at": "2024-09-01T12:06:14Z"
        },
        {
          "tag": "2.14.1",
          "kind": "patch",
          "published_at": "2024-07-31T09:10:37Z"
        },
        {
          "tag": "2.14.0",
          "kind": "minor",
          "published_at": "2024-07-23T16:56:55Z"
        },
        {
          "tag": "2.13.0",
          "kind": "minor",
          "published_at": "2024-07-12T12:53:56Z"
        },
        {
          "tag": "2.12.0",
          "kind": "minor",
          "published_at": "2024-06-26T15:26:12Z"
        },
        {
          "tag": "2.11.0",
          "kind": "minor",
          "published_at": "2024-04-08T07:38:01Z"
        },
        {
          "tag": "2.10.1",
          "kind": "patch",
          "published_at": "2023-12-11T13:16:47Z"
        },
        {
          "tag": "2.10.0",
          "kind": "minor",
          "published_at": "2023-11-27T18:18:08Z"
        },
        {
          "tag": "2.9.3",
          "kind": "patch",
          "published_at": "2023-11-14T16:21:25Z"
        },
        {
          "tag": "2.9.2",
          "kind": "patch",
          "published_at": "2023-06-19T16:54:15Z"
        },
        {
          "tag": "2.9.1",
          "kind": "patch",
          "published_at": "2023-06-08T10:15:50Z"
        },
        {
          "tag": "2.9.0",
          "kind": "minor",
          "published_at": "2023-06-07T14:04:08Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "ef902a525a983f6dde46c37c9f0c1a912da3a7cc",
          "body": "See #1378",
          "is_bot": false,
          "headline": "[TASK] Add test case for stringable component argument (#1379)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-06-14T12:00:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8dca97cbf34875343c73f45eaf319ca13b0f4376",
          "body": null,
          "is_bot": false,
          "headline": "[DOCS] Fix typo in ViewHelper code example (#1376)",
          "author_name": "Jonas Werner",
          "author_login": "svwerder",
          "committed_at": "2026-06-14T11:46:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "28c42c75b171aef196ddbe151b0d1146c290249d",
          "body": "symfony/polyfill-php84 1.33.0->1.34.0 adds RoundingMode stub [1].\n\nround() in PHP < 8.4 allows int as third argument only, and\nhas been extended with php 8.4 to allow int|RoundingMode.\n\nThe 'class_exists()' check in RoundViewHelper now suddenly\nreturns true when latest symfony/polyfill-php84 is load\n[…]\n 8.4 callback chain avoiding RoundingMode enum\naltogether, to avoid the symfony/polyfill-php84 influence.\n\n[1] https://github.com/symfony/polyfill-php84/commit/e4e3f1cc81b8b84a7c596f8817c6d186678e2884",
          "is_bot": false,
          "headline": "[BUGFIX] Fix RoundViewHelper with symfony/polyfill-php84 (#1373)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2026-04-16T17:09:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "66da09ba59c857b58851ba667c0c22d10304dc92",
          "body": "Currently, the Fluid parser is not ready to require the location\neverywhere, so the `@todo` is clarified.",
          "is_bot": false,
          "headline": "[TASK] Clarify todo in parser exception (#1369)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-08T09:09:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f1a7aa9759f4cd98f0d598cce73b5ecaec06da26",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] add more test for TemplateParser (#1367)",
          "author_name": "Matthias Vogel",
          "author_login": "Kanti",
          "committed_at": "2026-04-07T17:50:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "96c65692706fefb70108f7bf349f2c748f52c436",
          "body": "When removing the `<html xmlns` declarations from the template, line\nbreaks within the `<html>` tags were also removed. This lead to invalid\nline numbers reported by the template parser.\n\nWith this change, the affected `<html>` tag is replaced with the\nmatching number of newlines.",
          "is_bot": false,
          "headline": "[BUGFIX] Prevent shifting of line numbers (#1358)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-07T17:25:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ae092f1e6e3725e47fb9fc0133a32b540de35b25",
          "body": "This patch adds a dedicated CLI command to analyze Fluid templates for\nerrors or deprecations. Templates can be provided either as paths or\nvia STDIN, which enables deeper integration of the fluid CLI tool into\ncode editors and IDEs. Output can be either human-readable or\nmachine-readable as JSON.\n\n\n[…]\ntly, a shortcoming of both the warmup and the analyze command is\nthat no additional global Fluid namespaces can be provided. This needs\nfurther investigation and thus is not addressed with this patch.",
          "is_bot": false,
          "headline": "[FEATURE] CLI command to analyze Fluid templates (#1359)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-07T15:25:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f40ae370eae8c67839bc7f54f70c10674b69189d",
          "body": "Until now, Fluid's exceptions are unaware of the exact location in\nthe original template file that triggered the exception. This patch\nintroduces the necessary data structures and interfaces to accomplish\nthis.\n\nIn a first step, the already available context in the `TemplateParser`\nis now attached t\n[…]\n character numbers currently provided might not\nalways be accurate due to the mechanisms the parser currently uses\ninternally. This change creates the basis to tackle this in a more\nstructured manner.",
          "is_bot": false,
          "headline": "[TASK] Template location aware exceptions (#1366)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-07T15:20:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "100e885396b0e915c501e72fa5e41fcf8b7982f7",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Add infection for mutation coverage (#1323)",
          "author_name": "Matthias Vogel",
          "author_login": "Kanti",
          "committed_at": "2026-04-06T10:19:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "951d00e823b476494fb479b08deab0313e3e9567",
          "body": "Some new ViewHelpers didn't yet cross-reference to the TYPO3\ndocumentation.",
          "is_bot": false,
          "headline": "[DOCS] Add missing cross-references to TYPO3 reference (#1363)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-04T10:48:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c130f9eacdbbdf045087ea156fe6aaa7bd5c6d95",
          "body": "All ViewHelper classes now have a `@see` annotation that points to the\nViewHelper reference documentation. Also, the `@api` annotation has been\nadded where it was missing.",
          "is_bot": false,
          "headline": "[DOCS] Add links to ViewHelper reference (#1362)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-04T10:41:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a0b26b4cf180c0f774bb826a056187226dc6dced",
          "body": "`ViewHelperMetaFactory`, which is used both for CLI commands (such as\ncache warmup and schema generation) and for automatic documentation,\npreviously only collected the last instance of a PhpDoc annotation\non a ViewHelper class:\n\n```\n/**\n * @see link1\n * @see link2\n */\n```\n\nIn that example, the meta\n[…]\nh introduces a new flag that allows collecting all instances of\nannotations. When set, `ViewHelperMetadata` always stores arrays instead\nof strings, even if only one instance of the annotation exists.",
          "is_bot": false,
          "headline": "[TASK] Option to collect multiple PhpDoc annotations (#1361)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-03T19:24:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "79e043dec26f6db37ad31c494c9f514380a5138e",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Cover multiple @see annotations with test case (#1360)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-04-03T18:54:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "816016e9176d042a7a6e6da4411dbfc1dddfd27a",
          "body": "…357)",
          "is_bot": false,
          "headline": "[TASK] Add test case for undefined variable in ternary expression (#1…",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-31T14:48:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "954b6cd74b8cddfdef0dede140bb744f0b2b1490",
          "body": "Resolves: #1247",
          "is_bot": false,
          "headline": "[DOCS] Clarify scope of changelog (#1351)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-17T14:22:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dce7467c2bfd4c8fea3edbb7983664bdc6f51882",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Add exception codes to ViewHelper exceptions (#1347)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-11T11:10:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "81509636664f1165d4bbacd1750652c911470f84",
          "body": "If the path to the current template file is available, exceptions\nfrom ViewHelpers now also contain this information to make debugging\neasier. To achieve that, all ViewHelper exceptions are wrapped in\nan outer exception which extends the original exception message. This\nnew behavior can be disabled by registering a custom error handler\nin the rendering context.",
          "is_bot": false,
          "headline": "[TASK] Add file path to ViewHelper exception messages (#1346)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-09T17:38:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d3d9c26b02b3cd8c9715bf477d368c6ddb0897b",
          "body": "Previously, PHP code within the context of a template (most importantly\nViewHelpers, but also internal Fluid code) wasn't aware of the current\ntemplate context. This meant that exceptions couldn't refer to the\ntemplate file where the exception was actually triggered.\n\nThis change introduces the opti\n[…]\n files.\n\nIn follow-up patches, this path can be used to improve exception\nmessages within Fluid. It also allows users to access these values to\nimprove exception messages in their own implementations.",
          "is_bot": false,
          "headline": "[TASK] Provide current template path in renderingContext (#1337)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-09T13:24:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ec2c8702849d5f8fc3764fd13363dedcd61395a4",
          "body": "Several custom exceptions are introduced to indicate invalid ViewHelper\narguments. Their base class `InvalidArgumentException` extends from\n`ViewHelper\\Exception`, which makes it possible to catch them via\nFluid's error handlers. Previously, a lot of ViewHelpers used the\nglobal `\\InvalidArgumentExce\n[…]\n itself and by\nindividual ViewHelpers if a supplied argument value cannot be processed\nby the ViewHelper. We recommend that custom ViewHelpers also use this\nexception if they receive an invalid value.",
          "is_bot": false,
          "headline": "[TASK] Introduce dedicated exceptions for argument validation (#1344)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-09T13:13:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cb15a9d7458d5b25073e77b22343d08770874414",
          "body": "Use consistent syntax for `\\InvalidArgumentException`.",
          "is_bot": false,
          "headline": "[TASK] Unify exception usage in TagBuilder (#1345)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-07T16:35:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ffb251a159b7cc58f80eee6ee2740ecd1ee63b39",
          "body": "Version 4.4.2 is now officially compatible with Fluid 5.x.\n\n> composer req t3docs/fluid-documentation-generator:\"^4.4.2\" --dev",
          "is_bot": false,
          "headline": "[TASK] Update fluid-documentation-generator (#1343)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-07T11:02:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c2fd11f2cb85ace3957220c511c1f25944433305",
          "body": "In an effort to ease debugging, exceptions thrown by the Fluid parser\nnow contain the full path to the original template file. Previously,\nit could be quite hard to discover the affected template because of\nthe cryptic and internal templateIdentifier. Now, the full template\npath is given as an addit\n[…]\n high-level `TemplateView` class are encouraged to make use of the\nnew argument in `TemplateParser->parse()` and\n`TemplateParse->getOrParseAndStoreTemplate()` to provide the full\npath to the template.",
          "is_bot": false,
          "headline": "[TASK] Include template path in parser exceptions (#1336)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-07T10:32:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "aadb6ce7869f2b71464cb8aa2054908c440fb41d",
          "body": "* Enable a skipped test that seems to work fine now.\n* $this->creatMock() vs. self::createStub(): Mocks that declare\n  no expectations are stubs. phpunit is now more picky with\n  this, which is good to clarify things. The change switches\n  many cases to stubs. Places that mock system-under-test to t\n[…]\n fixture classes extending the abstract and new().\n* expects(self::any()) is deprecated. We switch to once() and\n  friends or remove some cases entirely since some of course\n  turn out to be obsolete.",
          "is_bot": false,
          "headline": "[TASK] Have notice and deprecation free phpunit v13 (#1342)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2026-03-06T22:42:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "80ebac94351c9c7c12ac5eb4e1f5ea0ecaeb1c0f",
          "body": "Do not randomize test order in phpunit.xml since that is\nannoying when actively working with the test code base. Have\na dedicated workflow job instead to add a randomized run.\n\nRaise phpunit.xsd to oldest common denominator and remove\nresolveDependencies attribute which is identical to the\ndefault value.",
          "is_bot": false,
          "headline": "[TASK] Order tests by default by default (#1341)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2026-03-06T21:23:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b305e7eda33edc631e1c99dbb8c855364e958b51",
          "body": "Allows phpunit v13 when PHP version fits.\n\n> composer req --dev friendsofphp/php-cs-fixer:^3.94.2\n> composer req --dev phpstan/phpstan:^2.1.40\n> composer req --dev phpstan/phpstan-phpunit:^2.0.16\n> composer req --dev phpunit/phpunit:\"^11.5.55 || ^12.5.14 || ^13.0.5\"\n> composer req --dev psr/container:^2.0.2\n> composer req --dev t3docs/fluid-documentation-generator:^4.4.1",
          "is_bot": false,
          "headline": "[TASK] Bump dev dependencies (#1338)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2026-03-06T19:53:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fb31cfe066f9807f818d054f67c74e10304cc31e",
          "body": "Resolves: #1244",
          "is_bot": false,
          "headline": "[DOCS] Add chapter about variable escaping (#1332)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-04T19:00:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "526092c411173c7183aebc1d17a229b8f84a9c78",
          "body": "This change aims to simplify debugging by providing improved exception\nmessages in cases where a template file cannot be resolved.\n\nPreviously, these exceptions lacked important context (e. g. which\ntype of template [template, partial, layout] is missing). Also,\nthe messages still suggested to the u\n[…]\nent exception classes and messages are now\nused for templates, partials and layouts, which helps during debugging.\nAlso, the exception messages have been streamlined, which also extends\nto components.",
          "is_bot": false,
          "headline": "[FEATURE] Clarify exceptions for missing templates (#1335)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-04T11:34:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "66183879e33830822f372801e4e2d83db1a0ae7d",
          "body": "Within `TemplatePaths`, a `InvalidTemplateResourceException` is thrown\nif no suitable template can be found based on the provided paths,\ncontroller and action. Previously, this has been part of\n`getTemplateSource()`, right before the template file is read.\n\nThis patch moves the validation one level \n[…]\nluid 6. Otherwise this change would have been breaking.\n\nIn a follow-up patch, this will be improved even further by providing\nthe user with a list of all possible template paths that have been\ntried.",
          "is_bot": false,
          "headline": "[TASK] Move around template file validation code (#1334)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-03T18:31:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "70f6eecafe7372ba762260eb7b4d7db799d880f9",
          "body": "A new interface `ComponentListProviderInterface` is added to Fluid,\nwhich allows component collections to not only resolve one specific\ncomponent, but also the reverse: When implemented,\n`getAvailableComponents()` returns a list of all components that are\npart of the collection. This can be useful f\n[…]\nat matches their custom folder structure. This will change in Fluid 6,\nwhere it will be assumed that users define both `resolveTemplateName()`\nand `getAvailableComponents()` consistently if necessary.",
          "is_bot": false,
          "headline": "[FEATURE] API to generate component listings (#1318)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-03-03T14:30:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b3f8a31faabd386a2911101fe19da0a389689796",
          "body": "The patch extends Fluid's own XSD schema generator classes to\nbe able to work with component definitions. This allows frameworks\nthat use Fluid components and are aware of all component collections\n(e. g. via DI) to generate XSD schema files for components.",
          "is_bot": false,
          "headline": "[TASK] Make ViewHelperMetadata compatible with components (#1331)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-26T16:06:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4e84db6f2f7824e81aa7c2ea7c5be9a33556c7b0",
          "body": "An option is added to `TemplateFinder` and `TemplatePaths` to get all\navailable templates without their file extension. This enables easier\nprocessing later, e. g. in the context of component collections.",
          "is_bot": false,
          "headline": "[TASK] Option to get available templates without extension (#1330)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-26T15:55:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c61416b4573f6b8d1acca0d01f5ebfe3c07e4087",
          "body": "This patch introduces new data structures that represent annotations\nfor ViewHelpers/Components or their individual arguments. The purpose\nis to be able to attach arbitrary information to definitions of\nViewHelpers/Components or arguments, either to pass them along as-is\nor to react to them within F\n[…]\nwritten to Fluid's template\ncache files, each annotation needs to implement the `compile()`\nmethod, which returns the PHP code that re-creates the annotation object\nwhen a template is read from cache.",
          "is_bot": false,
          "headline": "[FEATURE] Annotations API (#1314)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-24T11:21:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9d563f3b169593548b01f45447f74e7cf454a268",
          "body": "Due to an oversight, each component call from a template created its\nown instance of the responsible ViewHelperResolverDelegate. This is\nnot necessary, since resolver delegates are meant to be sharable.\n\nThis patch introduces the new `getResolverDelegate()` method, which\ncentralizes the already exis\n[…]\nrDelegateInstanceFromClassName()` are migrated to the\nnew method.\n\nNote that the performance impact wasn't relevant in TYPO3, since the\nunderlying DI implementation already shared the service objects.",
          "is_bot": false,
          "headline": "[TASK] Share resolver delegates in cached templates (#1319)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-20T13:34:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3d7b9920cc8695aed5c09e5e186beabb8cb8b033",
          "body": "… (#1305)\n\nWith #1288, the `UnsafeHTML` interface has been introduced, which prevents\nFluid's default output escaping if implemented by an object. In other Fluid\ninternals, objects that implement that interface are already stringified in\ncases where it increases compatibility with normal strings.\n\nT\n[…]\ntext (variables are not auto-converted if they should be compared\nstrictly).\n\nThis is a general enhancement and should not have consequences to loose\ncomparisons, which are commonly used in templates.",
          "is_bot": false,
          "headline": "[BUGFIX] Enhance boolean evaluation to check for UnsafeHTML instances…",
          "author_name": "Matthias Vogel",
          "author_login": "Kanti",
          "committed_at": "2026-02-20T13:32:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3f7634a5835a38a677477926549bc5b0f7292b1d",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Run phpunit tests in random order (#1322)",
          "author_name": "Matthias Vogel",
          "author_login": "Kanti",
          "committed_at": "2026-02-20T10:51:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2e4d7a7ade20427dcc6eb3dee026209906b4d9bb",
          "body": "Fluid's `BooleanParser` attempts to cover a specific edge case: If\ntwo objects should be compared, according to the code it should always\nbe a strict comparison. However, the condition that should have\naccomplished this depends on the variable content during the first\nrun. If a template is compiled \n[…]\nither uncached or cached\ntemplates would be correct, but never both. The new version delivers\nthe same results as cached templates before this change, so it should\nbe in line with real-world projects.",
          "is_bot": false,
          "headline": "[BUGFIX] Address inconsistencies in object comparisons (#1320)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-20T10:41:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "65e961e89d6ddefb945118b35b424629014760c8",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Improve naming of metadata factory tests (#1315)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-18T17:40:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "de298aea884f1a88d029fbdbcff6d1dc33d049a6",
          "body": "To simplify the code for further changes, constructor property\npromotion is now used in `ArgumentDefinition`. Also, compilation\nfor Fluid cache file is now handled within `ArgumentDefinition`.\nSelf-explaining comments are removed.",
          "is_bot": false,
          "headline": "[TASK] Consolidate ArgumentDefinition implementation (#1313)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-17T17:41:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cc132cfff67f98e9311a438efcdd064d34fdac13",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Improve return type annotation for VH creation (#1310)",
          "author_name": "Elias Häußler",
          "author_login": "eliashaeussler",
          "committed_at": "2026-02-17T15:01:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c16e48bf8043b40f7517f486830376b8067d3a7b",
          "body": null,
          "is_bot": false,
          "headline": "[DOCS] Document reserved variables in Fluid 5 (#1309)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-14T11:22:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "83779845a3398e3c9d0edd6a44c358b8bc8acf80",
          "body": null,
          "is_bot": false,
          "headline": "[DOCS] Document version for boolean attributes (#1306)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-14T11:17:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cf489f651e121d963051199c96055f1d822b3cdd",
          "body": "… without being escaped (#1288)\n\nFluid escapes variable output by default to prevent XSS. In some cases,\nhowever, values originate from a trusted/sanitized source (e.g. HTML\ngenerated from a sanitizer, CMS RTE output, a Markdown renderer with\na strict allow-list, …) and should be rendered as HTML wi\n[…]\nion unwraps `UnsafeHTML` to a string first,\n  so empty HTML values behave like empty strings in conditions\n  (e.g. `{content}` is false when it’s `''`).\n\nTests/examples have been adjusted accordingly.",
          "is_bot": false,
          "headline": "[FEATURE] UnsafeHTML interface to allow passing variables to template…",
          "author_name": "Matthias Vogel",
          "author_login": "Kanti",
          "committed_at": "2026-02-02T18:23:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5badb37e9b00f8ffd45b36a40d5aaa67591b9f08",
          "body": "`null` can safely be converted to an empty string, so it's fine to\nallow it as a base string for string replacement.\n\nResolves: #1279",
          "is_bot": false,
          "headline": "[BUGFIX] Allow null value as input for f:replace (#1282)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-02T18:12:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ee0790808bc83017ff2d745858a138748365d7ec",
          "body": "Since Fluid 5, ViewHelpers can assume that the types of their arguments\nare properly enforced by Fluid: Either by automatic casting for simple\ntypes or by throwing an exception. However, this is currently not the\ncase for `string`: Here, `StrictArgumentProcessor` still accepts\nstringable objects as \n[…]\nter:\n\n```\n$this->registerArgument('value', 'string|int|float|Stringable', '');\n```\n\nSince one specified goal of Fluid 5 is type safety within ViewHelpers,\nthis is considered a bugfix.\n\nResolves: #1099",
          "is_bot": false,
          "headline": "[BUGFIX] Cast stringable objects early for ViewHelper arguments (#1290)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-02T18:11:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5f1366e5c1fa8356c81e775b3f68eda3024d7566",
          "body": "Previously, duplicate template/partial/layout root paths were removed\nfrom the array to avoid potential duplicate lookups. However, this\nprevented reordering of those paths by adding one path multiple times\nto the same array, which would ideally increase its priority over\nother paths.\n\nThis patch re\n[…]\nbackported to Fluid 4. However,\nthis is highly unlikely, which is why this is not considered a\nbreaking change in Fluid 5.\n\nThis patch also clarifies comments to be able to simplify code with\nFluid 6.",
          "is_bot": false,
          "headline": "[BUGFIX] Don't remove path duplicates to allow reordering (#1298)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-02-02T18:10:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0456eb4b5aa7f1a5ae5a8425cac508ea8c2cd374",
          "body": "…296)\n\nResolves: #1284",
          "is_bot": false,
          "headline": "[TASK] Improve exception message for invalid ViewHelper arguments (#1…",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-01-26T15:40:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33c5a37b788b0b4cc308f9857dfdb058fb110ca0",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Apply new cgl rules (#1294)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-01-26T15:36:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ed03cf9ad7ecc5603f43e1f2bdbe7dadbf5171d7",
          "body": "Documentation is added for the new `*.fluid.*` file extension and the\nassociated fallback chain. File references throughout the documentation\nare adjusted to always use the new extension. Also, links to moved files\nare fixed.\n\nResolves: #1289",
          "is_bot": false,
          "headline": "[DOCS] Fluid file extension (#1292)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-01-21T17:05:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9c1454339cf707a9b4d6920bc602e4423145a339",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Add stringable tests for StrictArgumentProcessor (#1291)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-01-21T14:28:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2aa9f1d4063d8c9bff7a90927413c148739e39e0",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Add test case for template name fallbacks (#1287)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2026-01-14T17:40:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "993b77a2a7d9392e024b9980c8462e40c125c9cf",
          "body": "Fluid 5 disallows variable names that start with an underscore. While\nthis is already enforced in `StandardVariableProvider` for setting\nsuch variables, this change now also triggers an exception if a\nvariable with an invalid name is accessed.\n\nThis is probably a temporary change to be removed with Fluid 6. For now,\nit allows the `TemplateValidator`, which is used during template\nwarmup, to discover this issue during parse time, and to let users\nknow about affected templates.\n\nResolves: #1263",
          "is_bot": false,
          "headline": "[TASK] Allow TemplateValidator to discover underscore variables (#1283)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-12-16T17:26:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ae55cbdb8814e031908c9b34bc4a1a2f4dc8eaac",
          "body": "Since a Fluid namespace does not necesarily refer to an existing class\n(e. g. \"TYPO3Fluid\\Fluid\\ViewHelpers\" is not a valid PHP class), the\nPHPDoc annotation is removed from `getNamespace()`.\n\nThis enables comparing namespace strings with the result of\n`getNamespace()` without phpstan issues (e. g. \"[...] will always\nevaluate to false\").",
          "is_bot": false,
          "headline": "[TASK] Loosen PHPDoc type for Fluid namespaces (#1280)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-12-15T19:47:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fc82facd9838d6c645de4545dd220ef169240359",
          "body": "Due to the way the structure of components is extracted from template\nfiles, it was previously not possible to use a PHP constant or enum\ncase as default value for a component argument.\n\nThis patch adds the `<f:constant>` ViewHelper to the list of allowed\nViewHelpers for that pre-parsing step, which makes it now possible\nto use `<f:constant>` from within `<f:argument>`.",
          "is_bot": false,
          "headline": "[BUGFIX] Allow constants and enum cases as argument default (#1272)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-12-10T14:49:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1aa517a61646029b4e1029e2ff76aa0109b75c9d",
          "body": "…(#1274)",
          "is_bot": false,
          "headline": "[DOCS] Document `<f:argument>` does not work when rendering sections …",
          "author_name": "Daniel Corn",
          "author_login": "cundd",
          "committed_at": "2025-12-10T11:42:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aca11557d820b35536455253520ba596b35f1a38",
          "body": "The existing `BackedEnumExample` is renamed to `StringBackedEnumExample`\nto also cover int-backed enums with `IntBackedEnumExample`. The\nexisting tests for `<f:constant>` are extended to cover all enum\nvariants.",
          "is_bot": false,
          "headline": "[TASK] Extend enum test coverage (#1269)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-12-07T16:35:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "03ef568664db2802bbc60e5f1ca81f20340d56f7",
          "body": "Due to refactorings in the cache layer of Fluid, which were necessary\nto make cache warmup feasible, the cache identifiers have changed\nwith Fluid 5. This currently leads to parse errors when a template\nname starts with a number because the associated cache file and most\nimportantly the generated PH\n[…]\n \"template_\" to cache\nidentifiers. Other special characters are already dealt with in\n`TemplateCompiler`, so we only need to ensure that the identifier\nstarts with an alpha-character.\n\nResolves: #1266",
          "is_bot": false,
          "headline": "[BUGFIX] Ensure valid name for cache classes (#1268)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-24T09:27:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "18048d9e26375c114cc1a59d47f0ceef186194b2",
          "body": "Change AbstractViewHelper declaration\n\n`abstract public function render(): mixed;`\n\nback to\n\n`abstract public function render();`\n\nToo much fallout with too little benefit.\n\nRelated: #1219",
          "is_bot": false,
          "headline": "[TASK] Avoid mixed return in AbstractViewHelper->render() (#1264)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2025-11-18T13:35:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ee5b89dea88415860da6f7acf2d5f0ca50fcf53f",
          "body": "Previous Fluid versions already had a CLI command which could be used\nto warmup the cache for template files, e. g. during deployment.\nHowever, the previous implementation required a lot of additional\ncontext and mixed parsing/compilation and rendering state. The\nprevious warmup implementation has a\n[…]\nhe underlying API,\nnamely `TemplateFinder` for finding template files and\n`TemplateValidator`, which produces a validation report for each\ntemplate, are marked as `@internal` for now.\n\nResolves: #1103",
          "is_bot": false,
          "headline": "[FEATURE] Overhauled cache warmup command (#1224)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-13T11:05:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "31a451f44298bfbcba4ee42eba8a26095cbb2184",
          "body": "As a follow-up to #1258, all example templates are now using the new\nFluid file extension. In all places where the file extension isn't\nspecified explicitly, the fallback mechanism allows us to just rename\nthe templates without any other changes. However, for\n`setTemplatePathAndFilename()`, an explicit path is given, which\nneeds to be adjusted. Also, if the file extension is specified\nexplicitly when rendering a partial, this also needs to be adjusted\nmanually.",
          "is_bot": false,
          "headline": "[TASK] Use Fluid file extension in examples (#1261)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-11T17:16:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "42a07b76a351266d73852bd5475366aa6adfad38",
          "body": "Historically, Fluid has always used generic file extensions for\ntemplate files, such as `.html`, `.txt` or `.xml`. While this\nprovides IDE integration out-of-the-box, it makes it hard to\ndistinguish files that are interpreted by Fluid and others that\nare just text or html files.\n\nThis patch introduc\n[…]\nd templates, it also allows us to create better IDE\nintegrations in the future. Also, it enables us to scan a whole project\nfor Fluid templates, which makes cache warmup and linting tasks\nconfig-free.",
          "is_bot": false,
          "headline": "[FEATURE] Introduce optional .fluid.* file extension (#1258)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-11T16:52:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a83414309826673766bde38daf1f79f1bbef09cd",
          "body": "This patch adds a new `<f:contains>` ViewHelper to Fluid, which allows\nto check if a provided string or array contains a specified value.\nDepending on the input, this mimicks PHP's `in_array()` or `str_contains()`.\n\nThe initial version of this patch is intended to be backported to Fluid 4.\nIn a follow-up, the code and argument types can be improved for Fluid 5.\n\nResolves: #1125",
          "is_bot": false,
          "headline": "[FEATURE] <f:contains> ViewHelper (#1193)",
          "author_name": "Michael Staatz",
          "author_login": "staatzstreich",
          "committed_at": "2025-11-10T13:50:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "91f835138d52d3fc6de51c2f5d6611393feb50d8",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Cleanup example code (#1260)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-08T15:32:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f926ce229c58f0f13fb0000e43bd456c33641afd",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Test real-world setup in TemplatePathsTest (#1259)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-08T13:13:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8a675bcb65e8a5244cdf1b3c2e3543e0590954db",
          "body": "All path handling and resolving in Fluid is performed by the\n`TemplatePaths` class, which is attached to the current rendering\ncontext. While this class has already been simplified in the past,\nthe actual path resolving has largely stayed the same because it\nincludes edge cases that were moved over \n[…]\not be found.\n\nIn a follow-up patch, this will also allow us to introduce a custom\nfile extension for Fluid templates, which will then also be part of that\nfallback chain.\n\nResolves: #371\nRelated: #938",
          "is_bot": false,
          "headline": "[FEATURE] Overhaul template path resolving (#1243)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-04T16:07:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f5377f0fa84adf61bad4fbf222f08cd06b3e8743",
          "body": "Fluid has so far removed any CDATA sections from templates. This has\nbeen introduced with 978071f, without any clear indication why this\nwas done. This means that Fluid templates either expect CDATA sections\nto be removed or avoid them altogether since they don't do anything.\nThis gives us the oppor\n[…]\n,\ninstead three curly braces `{{{ }}}` can be used to access Fluid\nvariables, call ViewHelpers and use expressions. The CDATA keyword\nitself is removed from the output.\n\nResolves: #1012\nResolves: #808",
          "is_bot": false,
          "headline": "[!!!][FEATURE] Alternative Fluid syntax in CDATA (#1246)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-04T16:04:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a8cb13977042aee22f2ccdc04417b0532b2a3d44",
          "body": "Quite early in the development of Fluid, the decision has been made\nto remove `<![CDATA[...]]>` sections from templates. The exact reason\nremains unclear, as 978071f8f5484e01882d7c4c6d740064f22d51ef only\nmentions that this has been added, but not why:\n\n> - replace cdata sections with empty lines (in\n[…]\n is now\ndeprecated: From Fluid 5 onwards, CDATA sections will just remain in\nFluid templates untouched. Until then, a deprecation will be emitted\nto let users know that this will change in the future.",
          "is_bot": false,
          "headline": "[TASK] Deprecate CDATA removal from templates (#1231)",
          "author_name": "Michael Staatz",
          "author_login": "staatzstreich",
          "committed_at": "2025-11-03T18:29:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b09cf355b072aa56e96a3f5dc042445d048db02b",
          "body": "In preparation for the possible introduction of more internal\nconstants in Fluid, custom variable names that start with an\nunderscore are no longer allowed.\n\nFor Fluid 4, a deprecation will be introduced in a follow-up patch\nto prepare template authors for the upcoming change.\n\nRelated: #1166\nRelated: #1041",
          "is_bot": false,
          "headline": "[!!!][TASK] Disallow variables that start with a \"_\" (#1225)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-03T18:25:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "640c57cff9f046b59fa530e185ced5200057777e",
          "body": "In preparation for the possible introduction of more internal\nconstants in Fluid, custom variable names that start with an\nunderscore will no longer be allowed.\n\nFor Fluid v4, a deprecation is emitted. In a follow-up for Fluid v5,\nthe deprecation will be replaced with an exception.\n\nRelated: #1166\nRelated: #1041",
          "is_bot": false,
          "headline": "[TASK] Deprecate variables that start with a \"_\" (#1253)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-11-03T18:19:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8101bb04a438493ff5787cbb5a9f76b9cf817f93",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Remove a duplicate header comment (#1255)",
          "author_name": "Elias Häußler",
          "author_login": "eliashaeussler",
          "committed_at": "2025-11-01T11:11:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bd53a073ef487af0d000c94997826270f58a2bea",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Correct return value comment in `f:max` VH (#1254)",
          "author_name": "Elias Häußler",
          "author_login": "eliashaeussler",
          "committed_at": "2025-11-01T11:09:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ecdcabb67d31b9de164b240192146a289316d666",
          "body": "MinViewHelper and MaxViewHelper\n\nExamples\n```\n<f:min value=\"{0: '1', 1: '2', 2: '3'}\" />\n<!-- 1 -->\n\n<f:max value=\"{0: '1', 1: '2', 2: '3'}\" />\n<!-- 3 -->\n```",
          "is_bot": false,
          "headline": "[FEATURE] Add f:min and f:max ViewHelpers (#1245)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-10-31T16:09:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "58bd87b3dea0ee1c88550f1d350dce4f3c2acaaf",
          "body": null,
          "is_bot": false,
          "headline": "[DOCS] Warn about using f:form.<something> in Components (#1250)",
          "author_name": "Lina Wolf",
          "author_login": "linawolf",
          "committed_at": "2025-10-15T12:56:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ffc4a8eb80653acf85ce2186a685772d92d6bab4",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Increase test coverage for template path resolving (#1241)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-09-21T16:38:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4dc0cc54007d0867ad0bc57578b5c0859ff0966b",
          "body": "With the `LenientArgumentProcessor`, which was previously used for\nViewHelper arguments, it was already possible to specify multiple\ntypes for an argument. However, that definition was silently ignored\nduring validation (see `ImageViewHelper` in TYPO3 Core).\n\nWith the introduction of the `StrictArgu\n[…]\nine the desired type automatically. Thus,\nif union types are used, all possible types need to be specified\nexplicitly and need to be dealt manually in the ViewHelper's\nimplementation.\n\nResolves: #1130",
          "is_bot": false,
          "headline": "[FEATURE] Support union types for ViewHelper and component API (#1226)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-09-16T14:46:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b4d31333ee61944c97bd4faef0fb018b450d2470",
          "body": "Type declarations are added to all ViewHelper methods as well as\nall properties that are considered internal and are most likely not\nredefined directly by a ViewHelper implementation. Three properties\nare left out intentionally, since they are currently part of the\nViewHelper API:\n\n* `AbstractViewHe\n[…]\nHelper::$escapeChildren`\n* `AbstractTagBasedViewHelper::$tagName`\n\nAdding type declarations to those properties would make it impossible\nto create ViewHelpers that are compatible with Fluid v4 and v5.",
          "is_bot": false,
          "headline": "[!!!][TASK] Add type declarations to ViewHelper classes (#1219)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-09-16T13:39:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ccff4a587599899ee8a43ce7cc9ab5117c9387db",
          "body": "RoundViewHelper, CeilViewHelper and FloorViewHelper provide three different ways of rounding to Fluid template.\n\nExamples\n\n```\n<f:round value=\"123.456\" /> <!-- Outputs 123.46 -->\n<f:ceil value=\"123.456\" /> <!-- Outputs 124 -->\n<f:floor value=\"123.456\" /> <!-- Outputs 123 -->\n```\n\nThis continues the work of Pullrequest:\n[[FEATURE] Add f:round, f:ceil and f:floor ViewHelpers #868](https://github.com/TYPO3/Fluid/pull/868)",
          "is_bot": false,
          "headline": "[FEATURE] Add f:round, f:ceil and f:floor ViewHelpers (#1220)",
          "author_name": "Michael Staatz",
          "author_login": "staatzstreich",
          "committed_at": "2025-09-16T13:17:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "856b0811ed113e5b9bf30d4f28d30099155fed92",
          "body": "Because of deprecations and other prerequisites in v4, we are now\nable to accumulate all ViewHelper-related validation code in\n`ViewHelperInvoker`.",
          "is_bot": false,
          "headline": "[!!!][TASK] Accumulate validation code in ViewHelperInvoker (#1216)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-09-16T12:51:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3205b57fa86c3f045bc0ab7031b106fc3876910c",
          "body": "For compatibility reasons, Fluid interpreted tag attributes that were set\nto `null` as empty strings in `TagBuilder`, which resulted in an empty\ntag attribute (`data-attribute=\"\"`). With this patch, that behavior is\nchanged: `null` values now lead to the attribute being omitted from the\ntag, just like `false` does.\n\nBefore:\n\n```xml\n<my:tagBased data-attribute=\"{null}\" />\nResult: <div data-attribute=\"\"></div>\n```\n\nAfter:\n\n```xml\n<my:tagBased data-attribute=\"{null}\" />\nResult: <div></div>\n```",
          "is_bot": false,
          "headline": "[!!!][TASK] Remove tag attributes if set to null (#1233)",
          "author_name": "Bill.大狗",
          "author_login": "billdagou",
          "committed_at": "2025-09-16T12:14:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3c0131560abf04280f9146f43c23eb6789219e6d",
          "body": "This is a follow-up from #1236. The internal changes are now reflected\nin the public method signatures as well.",
          "is_bot": false,
          "headline": "[!!!][TASK] Don't allow null as template identifier in parser (#1239)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-09-13T13:24:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90f2f03397bfa1107c09f516388ff16c54c3eb09",
          "body": "This patch addresses various deprecations that were introduced in\nrecent dev versions of PHP 8.5. All changes should be non-breaking\nand thus can be backported to Fluid v4.\n\n* `TemplateParser` now uses empty strings instead of `null` as array\n  key for runtime cache. Public API will be adjusted in v\n[…]\n\n* GroupedForViewHelper ensures to use an empty string instead of\n  `null` for array key to avoid the deprecation and considered\n  non-breaking because php converted null-index to `\"\"` index\n  anyway.",
          "is_bot": false,
          "headline": "[TASK] Address deprecations introduced by PHP 8.5 (#1236)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-09-13T12:14:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "83a314972330ee876c2028c0cb104333908a8172",
          "body": "The method is never called or referenced. Also, there don't\nseem to be any usages of 3rd-party packages.",
          "is_bot": false,
          "headline": "[TASK] Remove unused resetState() method (#1217)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-22T10:03:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "060b4787f1dbcac42a642e7196a6b8333199ca41",
          "body": "If a component or ViewHelper argument is not required and is not\nsupplied in the ViewHelper call, Fluid takes care of filling in the\ndefault value. But this also happens if the argument is supplied and\nis set to `NULL`. This usually happens if an undefined variable is\nprovided to the ViewHelper. For\n[…]\ntrictArgumentProcessor` prevents the\nfallback from happening if the argument is supplied, but with `NULL`\nas value. This patch adjusts the `StrictArgumentProcessor` to also\npass `NULL` values through.",
          "is_bot": false,
          "headline": "[BUGFIX] Allow NULL for optional arguments with default (#1221)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-22T09:16:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e154ee806eea1579878ee278947502adc87ec5ca",
          "body": "This is a clean-up after #1173.",
          "is_bot": false,
          "headline": "[TASK] Remove obsolete $tagAttributes property (#1218)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-20T18:12:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "21ac61973dd0091efc45ab3067951a412aae2dca",
          "body": "This patch introduces new API methods on the RenderingContext to\nobtain and replace Fluid's argument processor implementation. By\ndefault, the StrictArgumentProcessor is used, but the\nArgumentProcessorInterface exists to provide an alternative\nimplementation. However, it might be a good idea wrap cu\n[…]\ne StrictArgumentProcessor by using\nthe decorator design pattern to ensure valid input types\nto ViewHelpers and components.\n\nThis is a breaking feature because of the interface change.\n\nResolves: #1105",
          "is_bot": false,
          "headline": "[!!!][FEATURE] Ability to replace argument processor (#1204)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-20T17:11:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7fd755e367f525f309bff2833b3e51dae6e306e5",
          "body": "Since Fluid v5 will ship with a new, improved implementation of\ncache warmup, the old code related to warmup has been deprecated\nin Fluid v4 and is now removed. The new cache warmup feature is\nadded in a follow-up patch.",
          "is_bot": false,
          "headline": "[!!!][TASK] Remove old cache warmup implementation (#1209)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-20T16:47:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c4218a45f83c8dafdaabc0e1db2e30388bb6b746",
          "body": "…#1189)\" (#1214)\n\nThis reverts commit 54cddfd80801ae100af0b33c6671d801b9d3847a.\n\nreact/promise 3.3.0 release fixed the issue.",
          "is_bot": false,
          "headline": "Revert \"[TASK] Apply react/promise patch to fix PHP 8.5 deprecation (…",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2025-08-20T12:45:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e36d4c2651eab8af6a6dfb265626555c4ed276d7",
          "body": "Fluid v4.2.0 introduced a new API to process component and ViewHelper\narguments (see #1062). To avoid breaking changes in Fluid v4 with\nhow ViewHelpers handle their arguments, a `LenientArgumentProcessor`\nhas been introduced which has been used exclusively for ViewHelpers.\nComponents have used the n\n[…]\n required, integer given\").\n\nThere might be consequences for custom ViewHelpers, however in\nmost cases this change will make a lot of custom validation code\nthat was necessary until Fluid v5 obsolete.",
          "is_bot": false,
          "headline": "[!!!][TASK] Strict argument processing for ViewHelpers (#1194)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-18T14:16:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8271df914934968442f96cd47e4353b33e0d1dd1",
          "body": "The current implementation of `AbstractViewHelper` includes\nFluid's validation logic for ViewHelper arguments in the public\nmethod `validateArguments()`. This method is called internally\nby each ViewHelper in `initializeArgumentsAndRender()`, just\nbefore initialization and rendering of the ViewHelpe\n[…]\nstom validation steps after the internal\nvalidation has been completed successfully. This should allow\nusers that previously overrode `validateArguments()` to\nmove their custom logic to the new event.",
          "is_bot": false,
          "headline": "[FEATURE] Introduce ViewHelperArgumentsValidated event (#1200) (#1213)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-18T14:11:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "65688c56d6a5f23d83eb4d7b77e5d7288b945ee3",
          "body": "In order to implement a reasonable cache warmup, the template\ncache needs to be independent of the context where the template\nwill be used later in the project. For cache files, this means that\nthey cannot limit how a template will be used later on\n(partial, layout or template).\n\nThis patch removes the context-dependent prefixes for cache\nfile names to achieve this.",
          "is_bot": false,
          "headline": "[TASK] Avoid context-dependent prefixes for cache files (#1205)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-18T14:03:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cc9d2c77010e43d74210bba59d9778229d73f0ee",
          "body": "Use alias offsetSet() instead: \"The SplObjectStorage::contains(),\nSplObjectStorage::attach(), and SplObjectStorage::detach() methods\nhave been deprecated in favour of SplObjectStorage::offsetExists(),\nSplObjectStorage::offsetSet(), and SplObjectStorage::offsetUnset()\nrespectively.\"\n\nReleases: main, 4.5",
          "is_bot": false,
          "headline": "[TASK] Avoid PHP 8.5 deprecation \\SplObjectStorage->attach() (#1212)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2025-08-18T14:00:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "31580e8d469a5d7b734bb84a65c66b0c84266101",
          "body": "Fluid v5 will have a straightforward way to warmup the cache of\nFluid templates. As preparation for that, all code related to the\nold cache warmup is now deprecated.\n\nThis includes the `<f:cache.warmup>` ViewHelper, which allowed\nto provide special context to templates during cache warmup.\nSince all\n[…]\n dependencies of Fluid templates have been\ndeprecated and will no longer be an issue with Fluid v5, this\nworkaround will no longer be necessary.\n\nCo-authored-by: Simon Praetorius <simon@praetorius.me>",
          "is_bot": false,
          "headline": "[TASK] Deprecate old cache warmup feature (#1211)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2025-08-18T13:34:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "65ef1d82edcccbcb7953bb5db31eb3a447728773",
          "body": "Two new ViewHelpers `<f:startsWith>` and `<f:endsWith>` are added to Fluid. `<f:startsWith>` checks if the subject string starts with a specified string. `<f:endsWith>` checks if the subject string ends with a specified string. These ViewHelpers extend the AbstractConditionViewHelper.\n\nArguments:\n\ns\n[…]\nHello World\">\n\n</f:startsWith>\n<f:endsWith search=\"World\" subject=\"Hello World\">\n\n</f:endsWith>\n\n<f:variable name=\"result\" value=\"{myVariable -> f:startsWith(search: 'Hello')}\" />\n```\n\nResolves: #1126",
          "is_bot": false,
          "headline": "[FEATURE] <f:startsWith> and <f:endsWith> ViewHelpers (#1170)",
          "author_name": "Michael Staatz",
          "author_login": "staatzstreich",
          "committed_at": "2025-08-17T16:31:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c90fffb2fa806f24d4d6f64c89a5d4c6dfef01f3",
          "body": "A new <f:merge> ViewHelper is introduced to Fluid, which merges two arrays, optionally recursively.\n\nArguments:\n\narray $array\narray $with\nbool $recursive\nSee also [the php array_merge()](https://www.php.net/manual/en/function.array-merge.php) and [the php array_merge_recursive()](https://www.php.net\n[…]\n.php) functions.\n\nExamples:\n\n```\n<f:variable name=\"merged\" value=\"{f:merge(array: input, with: toMerge)}\" />\n<f:variable name=\"merged\" value=\"{input -> f:merge(with: toMerge)}\" />\n```\n\nResolves: #1123",
          "is_bot": false,
          "headline": "[FEATURE] <f:merge> ViewHelper (#1206)",
          "author_name": "Michael Staatz",
          "author_login": "staatzstreich",
          "committed_at": "2025-08-17T16:08:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a264bd2b976f4c759543039adb1757673813b05f",
          "body": "In #1151, it was already clarified that the `HtmlspecialcharsViewHelper`\nis in fact not used internally by Fluid. This means that we can also\nget rid of the custom compilation logic, which makes maintainance\nunnecessarily hard.",
          "is_bot": false,
          "headline": "[TASK] Remove micro-optimization from HtmlspecialcharsViewHelper (#1197)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-15T15:54:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0a756cb838d0f073851e4a2570b73107b5df0ee3",
          "body": "Currently, the ViewHelper validation API calls the internal ViewHelper\nAPI to obtain its argument definitions for validation. However, the\nproper way is to use the `ViewHelperResolver`, since it is possible\nto redefine certain argument definitions there.\n\nThis is demonstrated and tested by the `CustomViewHelperResolver`\nin the examples. However, this example only worked until now because\nof the lenient validation implementation of ViewHelpers.",
          "is_bot": false,
          "headline": "[BUGFIX] Call proper API to obtain ViewHelper API (#1199)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-15T15:54:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7fc105cacaff2825366aedb318d50a35b10e6caa",
          "body": "The ViewHelper is called with a `string`, but the argument is declared\nas `integer`.",
          "is_bot": false,
          "headline": "[BUGFIX] Address bug in test ViewHelper",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-15T14:50:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d39fc164472acc12b9246e275a9c4817616c5841",
          "body": null,
          "is_bot": false,
          "headline": "[TASK] Apply new cgl rules",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-15T13:54:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1f8a8cdbdd51ab72850dce0168bfe07a8824b5ee",
          "body": "With TYPO3 v14, there will be a deeper integration of the new\ncomponents feature into TYPO3. At that point, TYPO3-specific\ndocumentation of components can be added to the official TYPO3\ndocumentation.\n\nFor now, we try to cover TYPO3-specific parts in the Fluid\ndocumentation by adding tips in the relevant places.",
          "is_bot": false,
          "headline": "[DOCS] Improve TYPO3-related sections of components docs (#1188)",
          "author_name": "Simon Praetorius",
          "author_login": "s2b",
          "committed_at": "2025-08-13T12:44:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "54cddfd80801ae100af0b33c6671d801b9d3847a",
          "body": "Dev dependency.\nThis has been fixed upstream but not released, yet.\n\nPHP:\nhttps://github.com/php/php-src/commit/5f8d648af6ef4e29a3c7f2b2029d08466c12bc6f\n\nReact/promise:\nhttps://github.com/reactphp/promise/commit/d3998c8a5d3cff0b39b2f332da550e996f35b947",
          "is_bot": false,
          "headline": "[TASK] Apply react/promise patch to fix PHP 8.5 deprecation (#1189)",
          "author_name": "Christian Kuhn",
          "author_login": "lolli42",
          "committed_at": "2025-08-13T12:15:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "866c192774e7367a4f58ef6d54e1c547f4dd94e2",
          "body": "Removed the `get` method entirely and enhanced `getByPath` to handle both local variables and chain traversal. Updated tests to cover the new behavior, improving test robustness by adding cases for nested and array-based paths.\n\nResolves: #1164",
          "is_bot": false,
          "headline": "[BUGFIX] Fix  path access in `ChainedVariableProvider::get` (#1165)",
          "author_name": "Sascha Egerer",
          "author_login": "sascha-egerer",
          "committed_at": "2025-08-12T13:05:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 38,
      "commits_last_year": 126,
      "latest_release_at": "2026-04-16T17:27:38Z",
      "latest_release_tag": "4.6.1",
      "releases_from_tags": false,
      "days_since_last_push": 46,
      "active_weeks_last_year": 26,
      "days_since_latest_release": 105,
      "mean_days_between_releases": 15.9
    },
    "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": "typo3fluid/fluid",
          "exists": true,
          "license": "LGPL-3.0-or-later",
          "keywords": [],
          "ecosystem": "packagist",
          "matches_repo": true,
          "registry_url": "https://packagist.org/packages/typo3fluid/fluid",
          "is_deprecated": false,
          "latest_version": "5.3.1",
          "repository_url": "https://github.com/TYPO3/Fluid",
          "versions_count": 117,
          "total_downloads": 16388135,
          "dependents_count": 90,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 401469,
          "first_published_at": null,
          "latest_published_at": "2026-04-16T17:09:54Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 105
        }
      ]
    },
    "popularity": {
      "forks": 107,
      "stars": 169,
      "watchers": 22,
      "fork_history": {
        "days": [
          {
            "date": "2015-09-16",
            "count": 1
          },
          {
            "date": "2015-09-18",
            "count": 1
          },
          {
            "date": "2015-09-24",
            "count": 1
          },
          {
            "date": "2016-01-29",
            "count": 1
          },
          {
            "date": "2016-02-03",
            "count": 1
          },
          {
            "date": "2016-03-01",
            "count": 1
          },
          {
            "date": "2016-03-05",
            "count": 1
          },
          {
            "date": "2016-04-04",
            "count": 1
          },
          {
            "date": "2016-04-07",
            "count": 1
          },
          {
            "date": "2016-09-16",
            "count": 1
          },
          {
            "date": "2016-09-21",
            "count": 1
          },
          {
            "date": "2017-01-30",
            "count": 1
          },
          {
            "date": "2017-02-10",
            "count": 1
          },
          {
            "date": "2017-03-19",
            "count": 1
          },
          {
            "date": "2017-04-08",
            "count": 1
          },
          {
            "date": "2017-05-14",
            "count": 1
          },
          {
            "date": "2017-07-05",
            "count": 1
          },
          {
            "date": "2017-07-11",
            "count": 1
          },
          {
            "date": "2017-07-28",
            "count": 1
          },
          {
            "date": "2017-07-30",
            "count": 1
          },
          {
            "date": "2017-09-27",
            "count": 1
          },
          {
            "date": "2017-10-19",
            "count": 1
          },
          {
            "date": "2017-10-28",
            "count": 1
          },
          {
            "date": "2017-12-06",
            "count": 1
          },
          {
            "date": "2017-12-07",
            "count": 1
          },
          {
            "date": "2017-12-29",
            "count": 1
          },
          {
            "date": "2018-01-08",
            "count": 1
          },
          {
            "date": "2018-01-15",
            "count": 1
          },
          {
            "date": "2018-01-18",
            "count": 1
          },
          {
            "date": "2018-02-08",
            "count": 1
          },
          {
            "date": "2018-02-28",
            "count": 1
          },
          {
            "date": "2018-05-08",
            "count": 1
          },
          {
            "date": "2018-05-29",
            "count": 1
          },
          {
            "date": "2018-05-30",
            "count": 1
          },
          {
            "date": "2018-07-18",
            "count": 1
          },
          {
            "date": "2018-12-05",
            "count": 1
          },
          {
            "date": "2019-03-13",
            "count": 1
          },
          {
            "date": "2019-03-28",
            "count": 1
          },
          {
            "date": "2019-04-08",
            "count": 1
          },
          {
            "date": "2019-05-15",
            "count": 1
          },
          {
            "date": "2019-06-19",
            "count": 1
          },
          {
            "date": "2019-06-20",
            "count": 3
          },
          {
            "date": "2019-06-22",
            "count": 1
          },
          {
            "date": "2019-07-31",
            "count": 1
          },
          {
            "date": "2019-08-03",
            "count": 1
          },
          {
            "date": "2019-09-25",
            "count": 1
          },
          {
            "date": "2020-01-08",
            "count": 1
          },
          {
            "date": "2020-01-29",
            "count": 1
          },
          {
            "date": "2020-03-29",
            "count": 1
          },
          {
            "date": "2020-04-30",
            "count": 1
          },
          {
            "date": "2020-05-27",
            "count": 1
          },
          {
            "date": "2020-10-27",
            "count": 1
          },
          {
            "date": "2020-12-16",
            "count": 1
          },
          {
            "date": "2021-04-28",
            "count": 1
          },
          {
            "date": "2021-05-04",
            "count": 1
          },
          {
            "date": "2021-05-12",
            "count": 1
          },
          {
            "date": "2021-06-02",
            "count": 1
          },
          {
            "date": "2021-06-08",
            "count": 1
          },
          {
            "date": "2021-08-30",
            "count": 1
          },
          {
            "date": "2021-10-21",
            "count": 1
          },
          {
            "date": "2021-10-26",
            "count": 1
          },
          {
            "date": "2021-11-15",
            "count": 1
          },
          {
            "date": "2021-11-19",
            "count": 1
          },
          {
            "date": "2022-02-07",
            "count": 1
          },
          {
            "date": "2022-05-26",
            "count": 1
          },
          {
            "date": "2022-07-14",
            "count": 1
          },
          {
            "date": "2022-07-29",
            "count": 1
          },
          {
            "date": "2022-07-30",
            "count": 1
          },
          {
            "date": "2022-08-05",
            "count": 1
          },
          {
            "date": "2022-09-08",
            "count": 1
          },
          {
            "date": "2022-09-20",
            "count": 1
          },
          {
            "date": "2022-11-10",
            "count": 1
          },
          {
            "date": "2022-12-09",
            "count": 1
          },
          {
            "date": "2023-01-30",
            "count": 1
          },
          {
            "date": "2023-03-22",
            "count": 1
          },
          {
            "date": "2023-04-18",
            "count": 1
          },
          {
            "date": "2023-04-26",
            "count": 1
          },
          {
            "date": "2023-05-11",
            "count": 1
          },
          {
            "date": "2023-11-24",
            "count": 1
          },
          {
            "date": "2023-12-01",
            "count": 1
          },
          {
            "date": "2023-12-27",
            "count": 1
          },
          {
            "date": "2024-01-12",
            "count": 1
          },
          {
            "date": "2024-03-14",
            "count": 1
          },
          {
            "date": "2024-05-21",
            "count": 1
          },
          {
            "date": "2024-09-27",
            "count": 1
          },
          {
            "date": "2024-10-18",
            "count": 1
          },
          {
            "date": "2025-02-11",
            "count": 1
          },
          {
            "date": "2025-03-27",
            "count": 1
          },
          {
            "date": "2025-04-20",
            "count": 1
          },
          {
            "date": "2025-04-27",
            "count": 1
          },
          {
            "date": "2025-05-05",
            "count": 1
          },
          {
            "date": "2025-05-19",
            "count": 1
          },
          {
            "date": "2025-05-22",
            "count": 1
          },
          {
            "date": "2025-07-29",
            "count": 1
          },
          {
            "date": "2025-08-02",
            "count": 1
          },
          {
            "date": "2025-08-04",
            "count": 1
          },
          {
            "date": "2025-08-07",
            "count": 2
          },
          {
            "date": "2025-08-09",
            "count": 1
          },
          {
            "date": "2025-08-29",
            "count": 1
          },
          {
            "date": "2025-09-04",
            "count": 1
          },
          {
            "date": "2025-09-05",
            "count": 1
          },
          {
            "date": "2025-09-09",
            "count": 1
          },
          {
            "date": "2026-02-19",
            "count": 1
          },
          {
            "date": "2026-04-25",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 107,
        "total_forks": 107
      },
      "star_history": null,
      "open_issues_and_prs": 72
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 42311,
      "source_files_sampled": 381,
      "oversized_source_files": 0,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "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": 11,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "packagist"
      ],
      "dependencies": [],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "ext-json",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "ext-mbstring",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "ext-simplexml",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "friendsofphp/php-cs-fixer",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "infection/infection",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "php",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpstan/phpstan",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpstan/phpstan-phpunit",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpunit/phpunit",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "psr/container",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "t3docs/fluid-documentation-generator",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 11,
        "direct_count": 0,
        "indirect_count": 11
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 13,
        "merged_prs": 924,
        "open_issues": 59,
        "closed_ratio": 0.818,
        "closed_issues": 265,
        "closed_unmerged_prs": 122
      },
      "bus_factor": 3,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "NamelessCoder",
          "commits": 343,
          "avatar_url": "https://avatars.githubusercontent.com/u/2228052?v=4"
        },
        {
          "type": "User",
          "login": "s2b",
          "commits": 258,
          "avatar_url": "https://avatars.githubusercontent.com/u/458524?v=4"
        },
        {
          "type": "User",
          "login": "lolli42",
          "commits": 229,
          "avatar_url": "https://avatars.githubusercontent.com/u/2178068?v=4"
        },
        {
          "type": "User",
          "login": "skurfuerst",
          "commits": 222,
          "avatar_url": "https://avatars.githubusercontent.com/u/190777?v=4"
        },
        {
          "type": "User",
          "login": "kdambekalns",
          "commits": 181,
          "avatar_url": "https://avatars.githubusercontent.com/u/95873?v=4"
        },
        {
          "type": "User",
          "login": "robertlemke",
          "commits": 104,
          "avatar_url": "https://avatars.githubusercontent.com/u/95582?v=4"
        },
        {
          "type": "User",
          "login": "afoeder",
          "commits": 23,
          "avatar_url": "https://avatars.githubusercontent.com/u/1125168?v=4"
        },
        {
          "type": "User",
          "login": "sbuerk",
          "commits": 20,
          "avatar_url": "https://avatars.githubusercontent.com/u/1453466?v=4"
        },
        {
          "type": "User",
          "login": "hlubek",
          "commits": 18,
          "avatar_url": "https://avatars.githubusercontent.com/u/33351?v=4"
        },
        {
          "type": "User",
          "login": "maddy2101",
          "commits": 16,
          "avatar_url": "https://avatars.githubusercontent.com/u/1925287?v=4"
        }
      ],
      "contributors_sampled": 100,
      "top_contributor_share": 0.211
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "build.yml",
        "test-documentation.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [
        ".php-cs-fixer.dist.php"
      ],
      "has_editorconfig": true,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": null,
            "reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "30 out of 30 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": 4,
            "reason": "Found 14/30 approved changesets -- score normalized to 4",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 37 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": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 1,
            "reason": "2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1",
            "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": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 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": "ef902a525a983f6dde46c37c9f0c1a912da3a7cc",
        "ran_at": "2026-07-30T22:49:36Z",
        "aggregate_score": 4.2,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-30T07:59:28Z",
      "oldest_open_prs": [
        {
          "number": 396,
          "created_at": "2018-07-16T09:21:56Z",
          "last_comment_at": "2018-07-16T10:45:28Z",
          "last_comment_author": "NamelessCoder"
        },
        {
          "number": 398,
          "created_at": "2018-07-26T13:48:29Z",
          "last_comment_at": "2019-03-25T12:22:12Z",
          "last_comment_author": "coveralls"
        },
        {
          "number": 469,
          "created_at": "2019-07-31T12:56:57Z",
          "last_comment_at": "2019-07-31T13:46:46Z",
          "last_comment_author": "mbrodala"
        },
        {
          "number": 572,
          "created_at": "2021-10-26T14:48:46Z",
          "last_comment_at": "2025-06-02T11:45:05Z",
          "last_comment_author": "s2b"
        },
        {
          "number": 671,
          "created_at": "2022-12-09T11:31:37Z",
          "last_comment_at": "2023-08-16T16:12:17Z",
          "last_comment_author": "spthiel"
        },
        {
          "number": 1052,
          "created_at": "2025-04-16T22:18:00Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 1229,
          "created_at": "2025-09-04T21:09:55Z",
          "last_comment_at": "2026-02-15T20:52:17Z",
          "last_comment_author": "schliesser"
        },
        {
          "number": 1234,
          "created_at": "2025-09-11T03:12:05Z",
          "last_comment_at": "2025-09-16T01:10:28Z",
          "last_comment_author": "billdagou"
        },
        {
          "number": 1271,
          "created_at": "2025-12-07T17:22:13Z",
          "last_comment_at": "2026-03-13T06:50:54Z",
          "last_comment_author": "mbrodala"
        },
        {
          "number": 1321,
          "created_at": "2026-02-19T17:32:25Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 1372,
          "created_at": "2026-04-15T17:13:17Z",
          "last_comment_at": "2026-04-16T17:30:49Z",
          "last_comment_author": "lolli42"
        },
        {
          "number": 1375,
          "created_at": "2026-04-24T05:37:03Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 1384,
          "created_at": "2026-07-01T08:30:27Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ],
      "last_merged_pr_at": "2026-06-14T12:03:57Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 177,
          "created_at": "2016-09-29T14:30:00Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 212,
          "created_at": "2016-10-27T06:06:11Z",
          "last_comment_at": "2016-10-27T11:07:13Z",
          "last_comment_author": "AndreasA"
        },
        {
          "number": 274,
          "created_at": "2017-03-02T13:38:13Z",
          "last_comment_at": "2023-11-24T16:34:29Z",
          "last_comment_author": "lolli42"
        },
        {
          "number": 280,
          "created_at": "2017-04-18T15:46:10Z",
          "last_comment_at": "2023-11-24T17:40:31Z",
          "last_comment_author": "s2b"
        },
        {
          "number": 336,
          "created_at": "2017-08-10T14:47:54Z",
          "last_comment_at": "2023-05-15T12:31:53Z",
          "last_comment_author": "masi"
        },
        {
          "number": 373,
          "created_at": "2018-02-27T08:17:27Z",
          "last_comment_at": "2018-12-07T15:16:55Z",
          "last_comment_author": "NamelessCoder"
        },
        {
          "number": 382,
          "created_at": "2018-03-21T14:59:30Z",
          "last_comment_at": "2023-11-24T17:07:41Z",
          "last_comment_author": "lolli42"
        },
        {
          "number": 391,
          "created_at": "2018-07-04T08:16:31Z",
          "last_comment_at": "2021-06-03T11:41:15Z",
          "last_comment_author": "aimeos"
        },
        {
          "number": 407,
          "created_at": "2018-09-28T09:19:39Z",
          "last_comment_at": "2021-01-22T12:53:14Z",
          "last_comment_author": "NamelessCoder"
        },
        {
          "number": 412,
          "created_at": "2018-10-22T09:51:41Z",
          "last_comment_at": "2023-11-24T17:19:23Z",
          "last_comment_author": "lolli42"
        },
        {
          "number": 417,
          "created_at": "2018-11-07T11:12:31Z",
          "last_comment_at": "2021-05-18T20:23:08Z",
          "last_comment_author": "bmack"
        },
        {
          "number": 428,
          "created_at": "2019-02-14T14:37:42Z",
          "last_comment_at": "2021-05-21T08:58:04Z",
          "last_comment_author": "hilburger"
        },
        {
          "number": 514,
          "created_at": "2020-03-06T21:06:23Z",
          "last_comment_at": "2021-05-20T19:18:32Z",
          "last_comment_author": "hilburger"
        },
        {
          "number": 522,
          "created_at": "2020-09-02T13:37:53Z",
          "last_comment_at": "2023-11-24T17:39:23Z",
          "last_comment_author": "s2b"
        },
        {
          "number": 533,
          "created_at": "2021-03-17T18:11:28Z",
          "last_comment_at": "2024-08-11T09:17:14Z",
          "last_comment_author": "s2b"
        },
        {
          "number": 556,
          "created_at": "2021-07-08T16:30:57Z",
          "last_comment_at": "2025-03-25T07:47:12Z",
          "last_comment_author": "mbrodala"
        },
        {
          "number": 590,
          "created_at": "2022-05-07T22:23:38Z",
          "last_comment_at": "2024-08-11T08:59:25Z",
          "last_comment_author": "s2b"
        },
        {
          "number": 938,
          "created_at": "2024-07-25T10:35:50Z",
          "last_comment_at": "2024-08-11T08:04:40Z",
          "last_comment_author": "s2b"
        },
        {
          "number": 953,
          "created_at": "2024-08-11T07:57:02Z",
          "last_comment_at": "2025-02-11T18:39:10Z",
          "last_comment_author": "s2b"
        },
        {
          "number": 975,
          "created_at": "2024-08-18T10:25:47Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/TYPO3/Fluid",
    "host": "github.com",
    "name": "Fluid",
    "owner": "TYPO3"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "excellent",
      "name": "Overall health",
      "note": "The weighted overall 68 is calibrated to 80 on the published index scale (record calibration 2026-08-02).",
      "notes": [
        {
          "code": "overall_calibration",
          "params": {
            "raw": 68,
            "calibrated": 80,
            "calibration": "2026-08-02"
          }
        }
      ],
      "value": 80,
      "inputs": {
        "security": 42,
        "vitality": 69,
        "community": 70,
        "governance": 79,
        "calibration": "2026-08-02",
        "engineering": 80,
        "ai_readiness": 41,
        "weighted_overall_raw": 68
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 69,
        "weight": 0.21,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "commits_last_year": 126,
              "human_commit_share": 1,
              "days_since_last_push": 46,
              "active_weeks_last_year": 26
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 46 days ago",
                "points": 18,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 46
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "26/52 weeks with commits",
                "points": 18,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 26
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "126 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 126
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1",
                "points": 1,
                "status": "partial",
                "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": 90,
            "inputs": {
              "releases_count": 38,
              "latest_release_tag": "4.6.1",
              "releases_from_tags": false,
              "days_since_latest_release": 105,
              "mean_days_between_releases": 15.9
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "38 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 38
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 105 days ago",
                "points": 27,
                "status": "partial",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 105
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~15.9 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 15.9
                    }
                  }
                ],
                "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": "exceptional",
            "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": 51,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 51 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 51
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "good",
        "name": "Community & Adoption",
        "value": 70,
        "weight": 0.17,
        "metrics": [
          {
            "key": "popularity",
            "band": "moderate",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "forks": 107,
              "stars": 169,
              "watchers": 22,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "169 stars",
                "points": 36.1,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 169
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "107 forks",
                "points": 16.9,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 107
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "22 watchers",
                "points": 7.4,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 22
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 70,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "readme_badges": null,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "readme_badge_services": [],
              "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 (LGPL-3.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "LGPL-3.0"
                    }
                  }
                ],
                "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": "excellent",
            "name": "Ecosystem adoption (downloads)",
            "note": null,
            "notes": [],
            "value": 88,
            "inputs": {
              "packages": [
                "typo3fluid/fluid"
              ],
              "dependents": 90,
              "ecosystems": "packagist",
              "total_downloads": 16388135,
              "monthly_downloads": 401469
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "401,469 downloads/month across packagist",
                "points": 74.7,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 401469,
                      "ecosystems": "packagist"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "90 packages depend on it",
                "points": 13.1,
                "status": "partial",
                "details": [
                  {
                    "code": "registry_dependents",
                    "params": {
                      "count": 90
                    }
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "good",
        "name": "Sustainability & Governance",
        "value": 79,
        "weight": 0.23,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "good",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 77,
            "inputs": {
              "bus_factor": 3,
              "contributors_sampled": 100,
              "top_contributor_share": 0.211
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "3 contributor(s) cover half of all commits",
                "points": 36,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 21% of commits",
                "points": 17.8,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 21
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "100 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 100
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 37 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Newcomer PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "newcomer_pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 77,
            "inputs": {
              "merged_prs": 924,
              "open_issues": 59,
              "closed_issues": 265,
              "prs_merged_7d": null,
              "prs_decided_7d": null,
              "prs_merged_30d": null,
              "prs_decided_30d": null,
              "issue_closed_ratio": 0.818,
              "closed_unmerged_prs": 122,
              "first_time_authors_30d": null,
              "first_time_prs_merged_30d": null,
              "first_time_prs_decided_30d": null
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "82% of issues closed",
                "points": 34.4,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 82
                    }
                  }
                ],
                "max_points": 42
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "924/1046 decided PRs merged",
                "points": 26.5,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 924,
                      "decided": 1046
                    }
                  }
                ],
                "max_points": 30
              },
              {
                "key": "newcomer_pr_acceptance",
                "name": "Newcomer PR acceptance",
                "detail": "no first-time contributor's PR decided in 30d",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_newcomer_prs",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "max_points": 13
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 14/30 approved changesets -- score normalized to 4",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "good",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 67,
            "inputs": {
              "followers": 117,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "TYPO3",
              "public_repos": 23,
              "account_age_days": 6274
            },
            "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": "117 followers of TYPO3",
                "points": 14.9,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 117,
                      "login": "TYPO3"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "23 public repos, account ~17 yr old",
                "points": 22.1,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 23
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 17
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "exceptional",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "typo3fluid/fluid"
              ],
              "ecosystems": "packagist",
              "any_deprecated": false,
              "min_days_since_publish": 105
            },
            "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 105 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 105
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "117 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 117
                    }
                  }
                ],
                "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": "excellent",
        "name": "Engineering Quality",
        "value": 80,
        "weight": 0.19,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "excellent",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": true,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "2 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": ".php-cs-fixer.dist.php",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".php-cs-fixer.dist.php"
                    }
                  }
                ],
                "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": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "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": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "weak",
        "name": "Security",
        "value": 42,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "weak",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Branch-Protection, Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "branch_protection",
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 42,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 4.2
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "30 out of 30 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 14/30 approved changesets -- score normalized to 4",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 37 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": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1",
                "points": 0.8,
                "status": "partial",
                "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 not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "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": "exceptional",
            "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"
              ],
              "commit_weight_rule": {
                "min_commits": 50,
                "min_commit_share": 0.1
              },
              "review_only_matches": 0,
              "below_threshold_exposures": [],
              "assessed_self_published_locations": 22
            },
            "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": "weak",
        "name": "AI Readiness",
        "value": 41,
        "weight": 0.04,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "weak",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.98,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "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": "98 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 98,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "weak",
            "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": 37,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": ".php-cs-fixer.dist.php",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".php-cs-fixer.dist.php"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "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": 42311,
              "source_files_sampled": 381,
              "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/381 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 381,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "weak",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "examples"
              ],
              "has_mcp_signal": false,
              "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": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "examples",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "examples"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
      }
    ],
    "classification": {
      "top": [
        "library"
      ],
      "labels": [
        "library"
      ],
      "scores": {
        "library": 6
      },
      "primary": "library",
      "evidence": [
        {
          "tier": "distribution",
          "label": "library",
          "source": "registry:packagist",
          "weight": 6
        }
      ],
      "artifacts": [],
      "confidence": "medium",
      "host_extension": false,
      "runs_as_process": false,
      "consumed_by_code": true
    },
    "metrics_version": "2.5.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-30T22:50:04.584181Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/t/TYPO3/Fluid.svg",
  "full_name": "TYPO3/Fluid",
  "license_state": "standard",
  "license_spdx": "LGPL-3.0"
}

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

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

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