)]}'
{
  "log": [
    {
      "commit": "c558140a0f654368a173fb4032876d50f316b900",
      "tree": "3c4ca5cac42bf2436d76e3f18b9174266ee17f88",
      "parents": [
        "f892ea93346f02e941390ee83ac4f9a833101408"
      ],
      "author": {
        "name": "Martin",
        "email": "martin.ku@skysource.com.tw",
        "time": "Thu Oct 29 23:14:22 2026 +0800"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Thu Oct 29 16:17:31 2026 +0100"
      },
      "message": "Fix spacing in primer.md Java language section"
    },
    {
      "commit": "f892ea93346f02e941390ee83ac4f9a833101408",
      "tree": "ce887808b2020c2df7347ebde8660f4b987e2455",
      "parents": [
        "13262925eeedd4be8fab693decd0a216a95b9033"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Oct 25 17:12:40 2026 +0100"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Sun Oct 25 21:13:20 2026 +0100"
      },
      "message": "WW-5811 docs: document the submission-action type, the cutover and step rules\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "13262925eeedd4be8fab693decd0a216a95b9033",
      "tree": "023828d5c1208e7a81db97fbf26eb4adfff2cb63",
      "parents": [
        "cf47f9fbff7006958287f32921a9e8847f1252ac"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Oct 25 16:06:45 2026 +0100"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Sun Oct 25 21:13:20 2026 +0100"
      },
      "message": "WW-5811 docs: document date min/max and temporal required HTML5 constraints\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "cf47f9fbff7006958287f32921a9e8847f1252ac",
      "tree": "7dd9365ffa504480d0f1f7a561171d528a74001f",
      "parents": [
        "ac9a677600fdd86910a7632afa0fd21e134480ce"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Oct 25 09:53:02 2026 +0100"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Sun Oct 25 13:25:49 2026 +0100"
      },
      "message": "WW-5816 docs: document the localdate validator and its annotation\n\nAdd pages for the localdate validator and @LocalDateRangeFieldValidator,\nlist them in the bundled validators and the annotations table, add\nlocalDateRangeFields to @Validations, and point LocalDate users to the\nnew validator from the date validator page.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "ac9a677600fdd86910a7632afa0fd21e134480ce",
      "tree": "207b44c84e6573560d760cff1b883b9710f32ebc",
      "parents": [
        "16927002dde88f3889ed40c61b5f9d5d11143ad1"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Oct 25 07:36:58 2026 +0100"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Sun Oct 25 07:59:45 2026 +0100"
      },
      "message": "WW-5814 docs: document date conversion formats and isoOffsetAware\n\nThe type conversion page said dates use the Locale\u0027s SHORT format. Add a\nDates section listing the formats each date type tries, the whole-input\nrule and format selection from WW-5812/WW-5813, the JDK locale-data\ncaveat, and the opt-in struts.converter.date.isoOffsetAware constant\nfrom WW-5814.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "16927002dde88f3889ed40c61b5f9d5d11143ad1",
      "tree": "d2bb20e341fe0f8a5fed9cfc5783e83a5650d356",
      "parents": [
        "22331deddcd6b87fd0b088dabfe4eaa3fd424fad"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 24 15:55:36 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Sat Oct 24 16:26:32 2026 +0200"
      },
      "message": "WW-5810 docs: document java.time support in datetextfield\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "22331deddcd6b87fd0b088dabfe4eaa3fd424fad",
      "tree": "a86aad31c52bb1542a4e791c8cb0bad19ec830ca",
      "parents": [
        "b9cba12bf3a24ead8ada6662a425c0f22f484f03"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 24 15:11:17 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Sat Oct 24 15:32:05 2026 +0200"
      },
      "message": "WW-5778 docs: document datetextfield in the html5 theme\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "b9cba12bf3a24ead8ada6662a425c0f22f484f03",
      "tree": "01faefd655d190cab3e02fdfbabef380719df53a",
      "parents": [
        "249dbcddb0ca368f9f09985741ca972fac0accd2"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 23 07:36:48 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Fri Oct 23 10:04:08 2026 +0200"
      },
      "message": "WW-5790 docs: two-phase copy skips constructor defaults\n\nCo-Authored-By: Claude Mythos 5.1 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "249dbcddb0ca368f9f09985741ca972fac0accd2",
      "tree": "102544eb32067ba2ca7aaf3ef1176543859f7ed7",
      "parents": [
        "62a692bcc99f8328b43d32089e213a828db48802"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu Oct 22 21:16:02 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Thu Oct 22 21:26:39 2026 +0200"
      },
      "message": "WW-4323 docs: ParameterNameAware narrows, never widens, the params checks\n\nThe Parameters Interceptor page claimed ParameterNameAware takes\nprecedence over the interceptor, which has not been true since\n2.3.16.1. Point per-action relaxation at the interceptor parameters,\nand correct the stale method names and the excludedValuePatterns\nparameter name.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "62a692bcc99f8328b43d32089e213a828db48802",
      "tree": "d9e8994b2c9db872a3e410ffbd4d7531db1e33df",
      "parents": [
        "897280dfb8772c4a02886040b799fc763d43d62d"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 17 09:24:06 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 17 09:24:06 2026 +0200"
      },
      "message": "WW-3717 docs: document the http-method action attribute (#360)\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "897280dfb8772c4a02886040b799fc763d43d62d",
      "tree": "67b5ce9f380933694c20552291cee7a81003a1d1",
      "parents": [
        "057777d3b9b7c64fa02421ccb209d3738827f453"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 16 10:02:44 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 16 10:02:44 2026 +0200"
      },
      "message": "WW-3526 docs: describe how to track file upload progress (#359)\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "057777d3b9b7c64fa02421ccb209d3738827f453",
      "tree": "7fa84c87b51e570125317f9f2dbc457a23ce097b",
      "parents": [
        "2f19a74c3229a3f7e0c1f6c3632dcba60354ba0f",
        "1d9729b3690724de6b43da89b91aa401d9c899ad"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Oct 14 13:12:53 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 14 13:12:53 2026 +0200"
      },
      "message": "Merge pull request #355 from hiteshbosamiya/patch-1\n\nAdd missing import in Register.java"
    },
    {
      "commit": "1d9729b3690724de6b43da89b91aa401d9c899ad",
      "tree": "7fa84c87b51e570125317f9f2dbc457a23ce097b",
      "parents": [
        "2f19a74c3229a3f7e0c1f6c3632dcba60354ba0f"
      ],
      "author": {
        "name": "Hitesh A. Bosamiya",
        "email": "45116032+hiteshbosamiya@users.noreply.github.com",
        "time": "Wed Oct 14 16:28:18 2026 +0530"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 14 16:28:18 2026 +0530"
      },
      "message": "Add missing import in Register.java"
    },
    {
      "commit": "2f19a74c3229a3f7e0c1f6c3632dcba60354ba0f",
      "tree": "25149763a78e2763c59627dc280a29d3de8eea9d",
      "parents": [
        "d60562e9cc56216a1da29a9fb7fe4b650926aef6",
        "a3cb16eae2e8d90b0624a4901598fdb395eb505b"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Oct 14 11:18:03 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 14 11:18:03 2026 +0200"
      },
      "message": "Merge pull request #354 from apache/WW-5770-scoped-convention-result-path\n\nWW-5770 docs: document the scopable Convention result path"
    },
    {
      "commit": "a3cb16eae2e8d90b0624a4901598fdb395eb505b",
      "tree": "25149763a78e2763c59627dc280a29d3de8eea9d",
      "parents": [
        "d60562e9cc56216a1da29a9fb7fe4b650926aef6"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Oct 14 07:42:18 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Oct 14 07:42:18 2026 +0200"
      },
      "message": "WW-5770 docs: document the scopable Convention result path\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "d60562e9cc56216a1da29a9fb7fe4b650926aef6",
      "tree": "7a5820b86edf3141628cb91a001a05c11bc6d788",
      "parents": [
        "bca057384098508d7cb3bc05c1797b8e0c72ce55",
        "7460873feed77ff354ee5f9eef9335435e15e520"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 12 20:51:06 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 20:51:06 2026 +0200"
      },
      "message": "Merge pull request #353 from apache/WW-5768-scopable-ui-theme\n\nWW-5768 docs: list struts.ui.theme and struts.ui.templateDir as scopable"
    },
    {
      "commit": "7460873feed77ff354ee5f9eef9335435e15e520",
      "tree": "7a5820b86edf3141628cb91a001a05c11bc6d788",
      "parents": [
        "bca057384098508d7cb3bc05c1797b8e0c72ce55"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 12 20:48:19 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 12 20:48:19 2026 +0200"
      },
      "message": "WW-5768 docs: list struts.ui.theme and struts.ui.templateDir as scopable\n\nReplace the \"no constant is scopable yet\" warning with the two core\nconstants, use struts.ui.theme in the scoped-constant examples, and\nadd the package override to the theme and template-directory\nprecedence lists.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "bca057384098508d7cb3bc05c1797b8e0c72ce55",
      "tree": "367050f119891ed3aa54fc8e1513036c0201c4f0",
      "parents": [
        "31a00069ab2b01d0cdcc14d12cfeec1d827ab67a",
        "b37d8d416dc2a2c82cf15b8506b8d963103d13bf"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 12 20:10:37 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 20:10:37 2026 +0200"
      },
      "message": "Merge pull request #352 from apache/WW-5767-scoped-constant-value-substitution\n\nWW-5767 docs: document value substitution in scoped constants"
    },
    {
      "commit": "b37d8d416dc2a2c82cf15b8506b8d963103d13bf",
      "tree": "367050f119891ed3aa54fc8e1513036c0201c4f0",
      "parents": [
        "31a00069ab2b01d0cdcc14d12cfeec1d827ab67a"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 12 20:03:38 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 12 20:03:38 2026 +0200"
      },
      "message": "WW-5767 docs: document value substitution in scoped constants\n\nScoped constant values now go through the same ${...} substitution\nas \u003cconstant\u003e. Also drop the note that Java-based configuration\ncannot select struts.scopedConstantProvider, fixed by WW-5766.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "31a00069ab2b01d0cdcc14d12cfeec1d827ab67a",
      "tree": "373c845f90ea7c60bbc0fffc415e9b256b47e3ae",
      "parents": [
        "092c94150606ad1a9218524fcf81891e22d09146"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Oct 11 16:24:56 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 16:24:56 2026 +0200"
      },
      "message": "WW-3476 docs: document package-scoped constants (#351)\n\n* WW-3476 docs: document package-scoped constants\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n* WW-3476 docs: publish missing struts-6.5.dtd\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n* WW-3476 docs: address review of scoped constants section\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "092c94150606ad1a9218524fcf81891e22d09146",
      "tree": "785b2d196ea2ba6b2f188af488c1de35b2c9618c",
      "parents": [
        "17ea4cc291df8dfff4794bf454efe1b2645bfd6a",
        "0fd8f138d10226f94a2742963a72fa004d47560c"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 16:14:58 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 16:14:58 2026 +0200"
      },
      "message": "Merge pull request #350 from apache/WW-3472-sitemesh-deprecation-notice\n\nWW-3472 docs: mark SiteMesh plugin as deprecated and removed"
    },
    {
      "commit": "0fd8f138d10226f94a2742963a72fa004d47560c",
      "tree": "785b2d196ea2ba6b2f188af488c1de35b2c9618c",
      "parents": [
        "17ea4cc291df8dfff4794bf454efe1b2645bfd6a"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 16:12:37 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 16:12:37 2026 +0200"
      },
      "message": "WW-3472 docs: mark SiteMesh plugin as deprecated and removed\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "17ea4cc291df8dfff4794bf454efe1b2645bfd6a",
      "tree": "6acbb4707678aab7e4d978cac78e3a3c8c0b4800",
      "parents": [
        "a0592ab4f68e533a8588213155cdc7f081fa438d",
        "baafb2e07ce52ca692b71108fb1a3c8b120f8bec"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 14:50:18 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 14:50:18 2026 +0200"
      },
      "message": "Merge pull request #349 from apache/WW-3464-wildcard-first-match-wins\n\nWW-3464 docs: the first matching wildcard mapping wins"
    },
    {
      "commit": "baafb2e07ce52ca692b71108fb1a3c8b120f8bec",
      "tree": "6acbb4707678aab7e4d978cac78e3a3c8c0b4800",
      "parents": [
        "a0592ab4f68e533a8588213155cdc7f081fa438d"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 14:45:13 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 14:45:13 2026 +0200"
      },
      "message": "WW-3464 docs: the first matching wildcard mapping wins\n\nThe framework resolves XML wildcard action mappings to the first pattern\nthat matches, in declaration order; the page claimed the last one wins\nand gave the placement advice backwards.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "a0592ab4f68e533a8588213155cdc7f081fa438d",
      "tree": "fee71b78abf8a44052ab5b3c30174cd641baa355",
      "parents": [
        "ab95721b00f31b480bf7b1bbfdc75fcce872edc4",
        "fe286c4f004a7e5632be7891a0b102622d3a5c21"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 12:49:55 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 12:49:55 2026 +0200"
      },
      "message": "Merge pull request #348 from apache/WW-3364-json-type-converters\n\nWW-3364 docs: describe opt-in type converters in JSON serialization"
    },
    {
      "commit": "fe286c4f004a7e5632be7891a0b102622d3a5c21",
      "tree": "fee71b78abf8a44052ab5b3c30174cd641baa355",
      "parents": [
        "ab95721b00f31b480bf7b1bbfdc75fcce872edc4"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 12:43:25 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Oct 10 12:43:25 2026 +0200"
      },
      "message": "WW-3364 docs: describe opt-in type converters in JSON serialization\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "ab95721b00f31b480bf7b1bbfdc75fcce872edc4",
      "tree": "62add3aa9c634e18049fd927081e1b1580d8814d",
      "parents": [
        "5829d8403be2d77c6fa12f71f15f5d6b6f84bac1"
      ],
      "author": {
        "name": "ⳕⲛτⲉⲅⲥⲉⳏτⲟⲅ 🕵🏻",
        "email": "192411347+g0w6y@users.noreply.github.com",
        "time": "Fri Oct 09 10:13:25 2026 +0530"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 06:43:25 2026 +0200"
      },
      "message": "Document AliasInterceptor\u0027s @StrutsParameter authorization (#347)\n\n* Document AliasInterceptor\u0027s @StrutsParameter authorization\n\nWW-5758 (apache/struts#1991) adds @StrutsParameter authorization to AliasInterceptor: its\nraw-request-parameter fallback follows struts.parameters.requireAnnotations like the Parameters\nInterceptor, and copying a value already resolved on the stack follows the opt-in\nstruts.chaining.requireAnnotations like the Chaining Interceptor.\n\nAdds a Parameter Authorization section to the Alias Interceptor page, mirroring the Chaining\nInterceptor page\u0027s existing section of the same name, including the transitionMode note the\nreview asked for (an alias target is always non-nested, so the same exemption applies). Adds an\nentry for the Alias Interceptor to the @StrutsParameter page\u0027s Where authorization applies list.\n\nVersion cited as 7.5.0 to match the pattern of the two prior related fixes (WW-5752, WW-5753)\nand the current pom.xml SNAPSHOT; WW-5758\u0027s Fix Version is not yet set, so this may need updating\nonce it is.\n\n* Fix factual error, contradictory wording, and review-link typo\n\nAddresses lukaszlenart\u0027s review on struts-site#347:\n\n- An alias target CAN be a nested path (an alias map value like \u0027bean.bar\u0027 is valid - nothing in\n  AliasInterceptor restricts it, confirmed against the merged code). The page previously claimed\n  \u0027always non-nested\u0027, which is wrong; transitionMode only exempts the non-nested case, so a\n  nested target still needs the annotation regardless of transitionMode.\n- Fixed \u0027always requires... governed by struts.parameters.requireAnnotations\u0027 - contradictory\n  wording, since with the setting off nothing is required.\n- Dropped \u0027separately-authorized\u0027 describing a stack-resolved source value - it can be any state\n  an earlier action holds, not necessarily something bound through an annotated setter.\n- Added an \u0027Upgrading an existing application\u0027 note: an app using the documented foo/bar example\n  needs bar annotated once struts.parameters.requireAnnotations is enabled, or the alias is\n  silently skipped.\n\n* Fix ModelDriven exemption claim and opt-in wording\n\nAddresses lukaszlenart\u0027s second review on struts-site#347:\n\n1. The ModelDriven exemption sentence claimed it applies unconditionally, which isn\u0027t true in\n   defaultStack (alias runs before modelDriven there, so the model isn\u0027t on the stack yet - the\n   check and the write both land on the action). Reworded to his exact suggested text: the\n   exemption only applies in a custom stack that places alias after modelDriven.\n2. \u0027once struts.parameters.requireAnnotations is enabled\u0027 read as opt-in; it\u0027s on by default since\n   7.0.0. \u0027silently skipped (logged at WARN)\u0027 was self-contradictory. Reworded to his suggested\n   text."
    },
    {
      "commit": "5829d8403be2d77c6fa12f71f15f5d6b6f84bac1",
      "tree": "0f858ab4ffd23187237f16f5fb4ef8eb896c86c6",
      "parents": [
        "84aea3847acf50f06177b7e8861848a60bf2ff6b",
        "132a369ec27a52144b1ab5427fd7027fec2d980c"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Tue Oct 06 14:43:04 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 14:43:04 2026 +0200"
      },
      "message": "Merge pull request #346 from apache/docs/bean-validation-message-keys\n\nWW-5757 docs: describe how the Bean Validation plugin resolves constraint messages"
    },
    {
      "commit": "132a369ec27a52144b1ab5427fd7027fec2d980c",
      "tree": "0f858ab4ffd23187237f16f5fb4ef8eb896c86c6",
      "parents": [
        "84aea3847acf50f06177b7e8861848a60bf2ff6b"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 16:33:16 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 16:36:35 2026 +0200"
      },
      "message": "WW-5757 docs: describe how the Bean Validation plugin resolves constraint messages\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "84aea3847acf50f06177b7e8861848a60bf2ff6b",
      "tree": "d7edcce44743e3a4331da8f8855acdfa31c931b8",
      "parents": [
        "257b2a29e453a6a5a5167b0567c4d953b02f0b36",
        "bb441536e82cf77dc1c2dd1092f5d81deecc3feb"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 09:56:54 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 09:56:54 2026 +0200"
      },
      "message": "Merge pull request #345 from apache/docs/announce-s2-075-to-s2-078\n\ndocs: announce security bulletins S2-075 to S2-078"
    },
    {
      "commit": "bb441536e82cf77dc1c2dd1092f5d81deecc3feb",
      "tree": "d7edcce44743e3a4331da8f8855acdfa31c931b8",
      "parents": [
        "2c77234cf5122b418287149609d35f41b5cd2088"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 09:26:49 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 09:26:49 2026 +0200"
      },
      "message": "docs: scope the S2-075 announcement to Struts 7 with the allowlist disabled\n\nS2-075\u0027s Affected Software limits the 7.x range to applications that\ndisable the OGNL allowlist, which is on by default; the announcement now\nsays so, as the S2-070 entry scoped its affected version.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "2c77234cf5122b418287149609d35f41b5cd2088",
      "tree": "8100b560b3835b30b67080dfb5eb8f11ce62f3ef",
      "parents": [
        "1a59ddf55c5c62bc1e8eaea9ae59c7dda8c9cb14"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 09:25:54 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 09:25:54 2026 +0200"
      },
      "message": "docs: list S2-075 to S2-078 in the Prior Releases table\n\nAdds the four bulletins published today to every affected row.\nAffected ranges are taken from the bulletins themselves:\n\n- S2-075: 2.0.0-2.3.37, 2.5.0-2.5.33, 6.0.0-6.11.0, 7.0.0-7.3.0\n- S2-076: 2.5.14-2.5.33, 6.0.0-6.11.0, 7.0.0-7.3.0, so 2.5 to 2.5.13\n  stay without it\n- S2-077: 2.1.8-2.3.37, 2.5.0-2.5.33, 6.0.0-6.11.0, 7.0.0-7.3.0\n- S2-078: 2.0.0-2.3.37, 2.5.0-2.5.33, 6.0.0-6.11.0, 7.0.0-7.3.0\n\nThe 7.3.0 and 6.11.0 rows, which previously carried an empty\nVulnerability cell, are now populated. Column padding is rewritten\nthroughout because the widest cell grew.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "1a59ddf55c5c62bc1e8eaea9ae59c7dda8c9cb14",
      "tree": "fb429f794873c24c74f9f4225d0ebd26365ba095",
      "parents": [
        "257b2a29e453a6a5a5167b0567c4d953b02f0b36"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 09:25:53 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Oct 05 09:25:53 2026 +0200"
      },
      "message": "docs: announce security bulletins S2-075 to S2-078\n\nFour bulletins were published on the cwiki on 5 October 2026, covering\nCVE-2026-104711 through CVE-2026-104714. All four are fixed in 7.4.0\nand 6.12.0, released on 2 October 2026.\n\nEach CVE gets its own dated entry so it can be linked individually, in\nthe S2-070 to S2-074 form. All four share a date, so every anchor\ncarries its bulletin number (a20261005-s2075 and onwards).\n\nOn the home page the security box now lists the new batch, each\nbulletin with its own announcement link and a short subject. The\nS2-070 to S2-074 batch moves into the right-hand slot vacated by\nS2-069, the oldest item shown, condensed to one paragraph so the row\nstays balanced.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "257b2a29e453a6a5a5167b0567c4d953b02f0b36",
      "tree": "b0db42a9c22b7db8a5ee998f285ce7381458075e",
      "parents": [
        "56b59ab9e716cdc518219691dbad43df1fb205ec"
      ],
      "author": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Fri Oct 02 10:58:17 2026 +0000"
      },
      "committer": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Fri Oct 02 10:58:17 2026 +0000"
      },
      "message": "Updates Maven site by Jenkins\n"
    },
    {
      "commit": "56b59ab9e716cdc518219691dbad43df1fb205ec",
      "tree": "67a114a508129a33be02cedddce2cefba135e4a4",
      "parents": [
        "75cbc859ba175928a14a70574c8f58c15c705cdb",
        "125ba2d239056bb1e17cf606665c8395c113293f"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukasz.lenart@gmail.com",
        "time": "Fri Oct 02 12:46:22 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 12:46:22 2026 +0200"
      },
      "message": "Merge pull request #344 from apache/docs/announce-7.4.0-6.12.0\n\ndocs: announce Struts 7.4.0 and 6.12.0 General Availability"
    },
    {
      "commit": "125ba2d239056bb1e17cf606665c8395c113293f",
      "tree": "67a114a508129a33be02cedddce2cefba135e4a4",
      "parents": [
        "75cbc859ba175928a14a70574c8f58c15c705cdb"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 12:20:58 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 12:20:58 2026 +0200"
      },
      "message": "docs: announce Struts 7.4.0 and 6.12.0 General Availability\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "75cbc859ba175928a14a70574c8f58c15c705cdb",
      "tree": "e7f6f7092637edb3b7d5a1a7b68fe5abc754fc71",
      "parents": [
        "f0e3cdeb8b584a9fd0d1179e70afbdb5354cecf9",
        "63cb0f90acf9248eee44720f9d950765f9fa5cd5"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 12:18:28 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 12:18:28 2026 +0200"
      },
      "message": "Merge pull request #343 from apache/docs/struts-7.4.0-content-audit\n\ndocs: 7.4.0 and 6.12.0 content audit"
    },
    {
      "commit": "63cb0f90acf9248eee44720f9d950765f9fa5cd5",
      "tree": "e7f6f7092637edb3b7d5a1a7b68fe5abc754fc71",
      "parents": [
        "feeee621aebb49e72e34e086051edc4561b38717"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:17:20 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:08 2026 +0200"
      },
      "message": "WW-5729 docs(jasperreports): report parameters fall back to the value stack again\n\nValueStackShadowMap overloaded get/containsKey from 6.0.0 to 7.3.0, so\nJasperReports never saw the value-stack fallback. 7.4.0 restores it,\nwhich changes what a report parameter named like an action property\nreceives.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "feeee621aebb49e72e34e086051edc4561b38717",
      "tree": "aa0c41237145bf7f0d9d1972012ce294b0107050",
      "parents": [
        "cee8c99d6e7cfff88399d34eef4a77bfe1fdede9"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:17:07 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:08 2026 +0200"
      },
      "message": "WW-1742 docs(execAndWait): run one background process per browser tab\n\n7.4.0 documents overriding getBackgroundProcessName in the interceptor\nJavadoc instead of shipping a tokenized interceptor; the site page now\ncarries the same example and its two caveats.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "cee8c99d6e7cfff88399d34eef4a77bfe1fdede9",
      "tree": "a40dfd1d1f83f98a9f66e626ecaf352eb8617ff7",
      "parents": [
        "348770cd90ea65aaa9a00c6cf2196c4d7e384327"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:16:49 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:08 2026 +0200"
      },
      "message": "WW-5707 docs: flag the deprecated restful mappers in the CompositeActionMapper example\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "348770cd90ea65aaa9a00c6cf2196c4d7e384327",
      "tree": "c59a49bb5e816636d2b96d72c425866d3c225a0c",
      "parents": [
        "832cc639017bd2bf9ae1b318bbf806e07e67cd3e"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:16:49 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:08 2026 +0200"
      },
      "message": "WW-5707 docs: the restful action mappers are deprecated\n\nBoth legacy mappers are deprecated for removal in 7.4.0 and 6.12.0 in\nfavour of the REST plugin.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "832cc639017bd2bf9ae1b318bbf806e07e67cd3e",
      "tree": "10b102090d617a8dbd942092c284f5f967c1c191",
      "parents": [
        "8b604ff36efca23e6f47df47f55277209f419a31"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:16:32 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:08 2026 +0200"
      },
      "message": "WW-5712 docs: REST any-setter authorization, member-name matching and fluent setters\n\nThe Jackson any-setters section still described the sink as uncovered;\n7.4.0 covers it behind struts.rest.anySetter.requireAnnotations and\n@StrutsParameter(allowDynamicKeys \u003d true). Also records that REST body\nproperties are authorized by Java member name (WW-5715), that the\n@JsonIdentityInfo id and merged polymorphic properties are now checked\n(WW-5727, WW-5726), and that annotations on fluent setters count\n(WW-5709).\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "8b604ff36efca23e6f47df47f55277209f419a31",
      "tree": "e029be0457371e2c2eb88d8021f0b4788ea6ebef",
      "parents": [
        "824542e3cd6559e2770cfcd869697c31f91b7f49"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:15:50 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:08 2026 +0200"
      },
      "message": "WW-5735 docs(jasperreports7): applications declare jasperreports themselves from 7.4.0\n\nThe plugin now declares net.sf.jasperreports:jasperreports as provided,\nso it no longer arrives transitively. The Installation section claimed\nthe plugin brought it along; it now lists the dependency and carries an\nupgrade callout for 7.1.0-7.3.0 users.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "824542e3cd6559e2770cfcd869697c31f91b7f49",
      "tree": "c8f1f32106ec196df980bd3f7e1cd16453acda1d",
      "parents": [
        "a378953b4263dd142a7b79a2d1c211f17ec28d22"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:15:13 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:08 2026 +0200"
      },
      "message": "WW-5718 docs(bean-validation): beanValidationDefaultStack gains resource isolation\n\nFrom 7.4.0 and 6.12.0 the stack contains coep, coop and fetchMetadata;\nthe callout gives the upgrade step for actions that serve cross-site\nrequests.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "a378953b4263dd142a7b79a2d1c211f17ec28d22",
      "tree": "28a84483f2e9ff820263f0ccf8bf31ff63f1da14",
      "parents": [
        "f0e3cdeb8b584a9fd0d1179e70afbdb5354cecf9"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 10:15:05 2026 +0200"
      },
      "committer": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Oct 02 11:16:07 2026 +0200"
      },
      "message": "WW-5718 WW-5723 docs(rest): body size limit and resource isolation in restDefaultStack\n\nDocuments struts.rest.content.maxLength and the coep, coop and\nfetchMetadata interceptors in restDefaultStack, both from 7.4.0 and\n6.12.0, with the upgrade step each one needs. The new constants join\nthe Settings table.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "f0e3cdeb8b584a9fd0d1179e70afbdb5354cecf9",
      "tree": "77302a73a6b01aa67afe7725a108fe6768b66dc1",
      "parents": [
        "096e475d6d040ac2458625336563966ae23b6571"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu Sep 24 18:28:52 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 24 18:28:52 2026 +0200"
      },
      "message": "ci: remove stale files from the staged site on each deploy (#342)\n\nThe staging deploy copied _site over content/ without clearing it, so\nfiles removed from the site were never removed from asf-staging. Staging\nstill serves downloads.html (renamed in 2017), a 2019 migration/ page\nthat never existed on any branch, and 3,942 Maven site files for plugins\nand classes Struts 7 dropped. Replace content/ in full, as the javadocs\njob already does for source/maven and as the buildbot does for asf-site.\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "096e475d6d040ac2458625336563966ae23b6571",
      "tree": "c782cb95f7c470cae6383a66dff0223de7c8af74",
      "parents": [
        "18974a0b2905cbf17260f27ad483eb3f7877f9ac"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu Sep 24 18:06:01 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 24 18:06:01 2026 +0200"
      },
      "message": "WW-5732 docs: the JasperReports 7 format is matched case-insensitively from 7.4.0 (#341)\n\nMatches apache/struts#1922: JasperReport7Result retries the exporter lookup\nwith the lower-cased format when there is no exact match, so upper-case\nvalues carried over from the 6.x plugin (CSV, PDF) resolve again. Lower-case\nstays the canonical spelling; keeps a note on the 7.3.0 case-sensitive\nbehavior for readers on that release.\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "18974a0b2905cbf17260f27ad483eb3f7877f9ac",
      "tree": "66522f83a93883e70a3f10510f07bf04e89ec5ef",
      "parents": [
        "cf39ab70f1692f5b4b8332dd503e35ecc50274d4"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu Sep 17 08:52:56 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 08:52:56 2026 +0200"
      },
      "message": "WW-5743 docs: the ** count is the first specificity key from 7.4.0 (#340)\n\nMatches apache/struts#1962: the Convention plugin\u0027s most-specific-first\nordering now consults the path-spanning ** count before the wildcard-token\nand literal counts, so `a/*/*` ranks ahead of `a/**`. Keeps a note on the\n7.3.0 order for readers on that release.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "cf39ab70f1692f5b4b8332dd503e35ecc50274d4",
      "tree": "41f223a03450b09858a687a0d5b932ca7fb2f923",
      "parents": [
        "82878e354fa2cfccb27f2c1cbabaf48f39ff8f5d"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu Sep 17 07:16:54 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 07:16:54 2026 +0200"
      },
      "message": "WW-5713 docs: the Tiles OGNL prefix is disabled by default (#339)\n\nDocuments the fail-closed OGNL: expression language, the S2: migration\npath and the per-application struts.tiles.ognl.legacy.enabled escape\nhatch shipped in apache/struts#1890.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "82878e354fa2cfccb27f2c1cbabaf48f39ff8f5d",
      "tree": "51a0ab5efb5ad4326998c7e7915368a0a528e4f1",
      "parents": [
        "1ab2953aac68cfbfc55baca71e0d5d8cccb2fb8c"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Sep 16 08:56:28 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 16 08:56:28 2026 +0200"
      },
      "message": "docs: value on form tags is a String attribute; Alt Syntax page is history (#338)\n\n* docs: value on form tags is a String attribute, not an expression\n\nThe \"value is an Object!\" section claimed that a textfield with\nvalue\u003d\"ca\" looks up a getCa property. It does not: UIBean resolves\nvalue through findValue(expr, String.class), which returns the literal\nunless it contains the %{} notation. Only checkbox (Boolean) and file\n(Object) evaluate value as an expression. The section contradicted the\nthree-rule summary on the same page and prompted WW-3338.\n\nAlso drops the pointer to the altSyntax option, removed in 2.6.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n\n* docs: rewrite the Alt Syntax page as history\n\nThe option was removed in 2.6 (WW-3877), but the page still described\nit in the present tense, including a per-request useAltSyntax flag that\nno longer exists. Keeps the before/after example as the explanation of\nwhy the %{} notation exists, and notes that pre-altSyntax examples of a\nbare property in a form tag\u0027s value survive in old documentation.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "1ab2953aac68cfbfc55baca71e0d5d8cccb2fb8c",
      "tree": "eddb5d94b95d514932101a3384440d71843ecce6",
      "parents": [
        "c6b187fb0765746b575bd01c160a1aed923390e9"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Sep 14 17:16:57 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 17:16:57 2026 +0200"
      },
      "message": "WW-5698 docs: a ModelDriven action\u0027s own members are not exempt from @StrutsParameter (#337)\n\nDocuments the 7.4.0 three-way rule and names transition mode as the\nmigration path.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "c6b187fb0765746b575bd01c160a1aed923390e9",
      "tree": "5c3f4f784d54c3ad49951c9c14a047d063255812",
      "parents": [
        "ee7a045946fad17e7cce73b0db8790968f089f73"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Sep 14 16:45:59 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 16:45:59 2026 +0200"
      },
      "message": "WW-5704 docs: required on radio/file is judged against the bound value (#336)\n\nCompanion to apache/struts#1939.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "ee7a045946fad17e7cce73b0db8790968f089f73",
      "tree": "2c49449cb4c825c16ce7216c7f8e984b31b29ad6",
      "parents": [
        "86a4d279c6358594675ef599f3a70267d1386bcf"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Sep 14 12:49:10 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 12:49:10 2026 +0200"
      },
      "message": "WW-5703 docs: describe the whitespace-only alternative in derived HTML5 patterns (#335)\n\nCompanion to apache/struts#1938.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "86a4d279c6358594675ef599f3a70267d1386bcf",
      "tree": "738e8b05804eea927a7fa1e6ad847ea3d0f6a6b1",
      "parents": [
        "cd473a2f8f70227c6782d122b91abc8a9528d654"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Sep 14 12:20:21 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 12:20:21 2026 +0200"
      },
      "message": "WW-5740 Visitor-nested constraint messages resolve like validation does (#334)\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "cd473a2f8f70227c6782d122b91abc8a9528d654",
      "tree": "a777ec1ff671677e754e633d5c9d4eca2acff4c5",
      "parents": [
        "259cb3780c8bc760a77a31763a467d352160c1d9"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Sep 14 08:45:39 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 08:45:39 2026 +0200"
      },
      "message": "WW-5702 Document the constraint provider\u0027s attribute hygiene rules (#333)\n\n- data-msg-* is rendered only on controls that submit a value, and only\n  for validator types that are plain attribute names\n- a provider cannot change type or override a developer-set attribute;\n  the type\u003d\"email\" example is replaced\n- \\- is accepted only inside a character class; []a] is rejected\n- the visitor row was stale since the visited object\u0027s validators now\n  apply to nested fields\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "259cb3780c8bc760a77a31763a467d352160c1d9",
      "tree": "a065955b412012ebc1db4b97336c9f47c8512eea",
      "parents": [
        "d9b7d93349e40faf0d60d61a2e166a7b78d76e35"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Sep 13 10:38:44 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 10:38:44 2026 +0200"
      },
      "message": "WW-5669 Document the CSP nonce source setting (#332)\n\n* WW-5669 docs(core): document the CSP nonce source setting\n\nThe setting was never on the CSP interceptor page under either name. Adds\na \"Nonce source\" section with the working name struts.csp.nonce.source,\nand a note that struts.csp.nonceSource (shipped inert in\ndefault.properties since 6.8.0) is honoured as a deprecated alias from\n6.12.0 / 7.4.0, so existing configs carrying it switch to request-scoped\nnonces on upgrade.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n\n* WW-5669 docs(core): the alias lands in 7.4.0 only\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "d9b7d93349e40faf0d60d61a2e166a7b78d76e35",
      "tree": "be43b13b43634ee0ce0cea9abc4fa7be825304e0",
      "parents": [
        "79467b8c01746f6e6b479d529f0d6d2ba3134f8c"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Sep 12 11:25:46 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 11:25:46 2026 +0200"
      },
      "message": "WW-5728 docs(jasperreports7): add a page for the JasperReports 7 plugin (#331)\n\nThe struts2-jasperreports7-plugin shipped in 7.1.0 (WW-5455) without a\nsite page; the plugins index only listed the JasperReports 6.x plugin.\n\nThe new page mirrors the existing one and is sourced from the Javadoc\nof JasperReport7Result and JasperReport7Constants, with two corrections\nthe Javadoc gets wrong: format values are the lower-case bean names\n(the exporter lookup is a case-sensitive container lookup, so the\nJavadoc\u0027s `CSV` example fails with \"No exporter found\"), and the PDF\nexporter is an optional dependency that applications must add. It also\ncovers what the Javadoc does not: the JasperReport7Aware hooks, adding\na format through a JasperReport7ExporterProvider bean, the two\nstruts.jasperReport7.* constants, and a migration list from the 6.x\nplugin. Custom exporters are documented as new format names only,\nbecause redeclaring a bundled bean name in struts.xml throws\nConfigurationException.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "79467b8c01746f6e6b479d529f0d6d2ba3134f8c",
      "tree": "977d76ee060ba61943aa2c701203405302e2a972",
      "parents": [
        "8945401288bed9fef8d5983198eddf38555c4952"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Sep 12 10:57:24 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 10:57:24 2026 +0200"
      },
      "message": "WW-3245 docs(jasperreports): describe filling from report parameters (#330)\n\nCompanion to apache/struts#1919: dataSource is no longer required, and a\nreport can be filled from its parameters alone (HIBERNATE_SESSION,\nCSV_INPUT_STREAM, REPORT_DATA_SOURCE, ...) when neither dataSource nor\nconnection is set.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "8945401288bed9fef8d5983198eddf38555c4952",
      "tree": "24839aaaa63f6c31e33db3ae2d83f87e4685d9b7",
      "parents": [
        "08e3ed4e3de735c77840d0e2d197ae7a6a2351c5"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Sep 12 10:08:02 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 10:08:02 2026 +0200"
      },
      "message": "WW-3226 docs: explain how alias and params ordering decides which value wins (#329)\n\nThe alias interceptor page never said what happens when a request carries\nboth the source name and the alias target, and its own example puts alias\nbefore basicStack, where the directly submitted parameter silently wins.\nDocument the ordering rule and the params-then-alias stack that makes the\nalias override, which is the behavior WW-3226 asked an overwrite flag for.\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "08e3ed4e3de735c77840d0e2d197ae7a6a2351c5",
      "tree": "37ada99665010ea9a488fbf07944e1585c30350e",
      "parents": [
        "46b81fd5f7a05d104f7fd654e5a315dc14ed98a1"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Sep 11 06:00:11 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 06:00:11 2026 +0200"
      },
      "message": "docs: scope the @StrutsParameter \"never set\" claim to named properties (#328)\n\nThe annotation page told readers that JSON and REST deserialization means\nunauthorized fields are never set on the target object. That is true of the\nproperties the deserializer binds by name, but a Jackson any-setter is a\nseparate sink that the REST plugin\u0027s authorization wrapper never wraps, so\nunknown keys routed to it are bound with no @StrutsParameter check at all --\nin the same request in which an ordinary unannotated setter on the same class\nis correctly rejected.\n\nQualify the bullet and document the gap in its own section, alongside the\nexisting creator-bound-properties note that covers the same class of problem.\nThe JSON plugin is unaffected: it does not use Jackson, so its own page\u0027s\nidentical wording stays accurate and is left alone.\n\n\nClaude-Session: https://claude.ai/code/session_012HF8BGrYmCVnqUdQJJ1XPM\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "46b81fd5f7a05d104f7fd654e5a315dc14ed98a1",
      "tree": "025089315b84488b8734898e692d5e23f29e128d",
      "parents": [
        "924768d174b70310f3f9118775345643083e6a1d"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu Aug 27 17:17:43 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Aug 27 17:17:43 2026 +0200"
      },
      "message": "docs: HTML5 constraint validation, deprecate the JavaScript validator (#326)\n\n* docs: document html5 constraint validation, deprecate the JS validator\n\nRewrites client-side-validation.md around the html5 theme\u0027s new HTML5\nconstraint-validation attributes (struts.ui.html5.constraints), including the\nnever-false-reject rule, the full validator-to-attribute mapping, the\ntrim\u003d\"false\"/caseSensitive\u003d\"true\" conditions on stringlength/regex, the\nnever-change-the-type rule, data-msg-* hooks, the requiredLabel/required\ndistinction, and the swappable HtmlConstraintProvider extension point.\n\nDeprecates the older generated-JavaScript client-side validator (xhtml/\ncss_xhtml themes, \u003cs:form validate\u003d\"true\"\u003e) per WW-5694, removed in 8.0.0 per\nWW-5696: deletes pure-java-script-client-side-validation.md, repoints its\ninbound links (xhtml-theme.md, css-xhtml-theme.md, ajax-client-side-validation.md)\nto the deprecated section of the rewritten page, adds deprecation banners to\nclient-validation-example.md and form-tag.md\u0027s validate attribute.\n\nDrops the deleted page\u0027s claim that client-side messages are not\ninternationalized: ValidatorSupport.getMessage resolves through\nDelegatingValidatorContext and textProviderFactory, so they always were.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: stop asserting a specific version for the html5.constraints default flip\n\nThe shipped javadoc and default.properties deliberately say the\nstruts.ui.html5.constraints default is \"expected to flip in a future major\nrelease\" rather than naming 8.0.0, since the release version is chosen at\nrelease time from the accumulated semver impact. The docs page asserted \"in\nStruts 8.0.0\" instead, which is a firmer commitment than the code itself\nmakes. Softened to match the code\u0027s wording, with WW-5696 linked so the claim\nstays traceable.\n\nAlso makes every other \"removed in 8.0.0\" claim (the JS validator\u0027s removal)\ncite WW-5694/WW-5696 inline rather than floating as a bare assertion. Naming\n8.0.0 for that removal is kept as-is: it\u0027s a major-version removal, already\ncommitted to in Form.java\u0027s own @Deprecated(since \u003d \"7.4.0\", forRemoval \u003d\ntrue) javadoc, and WW-5696 is filed against it.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: add the regex validator\u0027s fourth pattern gate, generalize the trim note\n\nThe regex row promised pattern whenever text-entry, caseSensitive\u003d\"true\",\ntrim\u003d\"false\" and ECMAScript-safe held, but StrutsHtmlConstraintProvider has a\nfourth gate: email and creditcard validators are excluded even then, since\nboth extend RegexFieldValidator but carry grammars the browser doesn\u0027t share.\n\nAlso generalizes the trim\u003d\"false\" explanation: StringLengthFieldValidator.trim\ndefaults to true just like RegexFieldValidator.trim, so minlength/maxlength are\nemitted just as rarely as pattern is, for the same reason (server measures/\nmatches the trimmed value, browser sees the raw one). The page previously\nwarned about this only for pattern, which understated stringlength\u0027s own\nreach. Reworked into one shared paragraph covering both.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: fix the stringlength example\u0027s direction (server accepts, browser blocks)\n\nThe previous sentence said a stringlength validator with maxLength\u003d\"4\" would\nreject \"abcd \" server-side after trimming — backwards. Trimmed to \"abcd\" (4\nchars), StringLengthFieldValidator.validateValue only rejects when\ntrimmedLength \u003e maxLengthToUse, and 4 \u003e 4 is false, so the server accepts it.\nThe paragraph exists to show the server-accepts/browser-blocks asymmetry that\nmakes emitting the constraint attribute risky if trim isn\u0027t false; an example\nasserting the opposite direction illustrated nothing.\n\nCorrected to state the server accepts \"abcd \" while a browser maxlength\u003d\"4\"\nwould stop the fifth character from ever being typed, matching the direction\nof the retained [a-z]+/\"abc \" regex example alongside it.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: redirect the removed pure-javascript page to its new section\n\nThe page was folded into client-side-validation.md as a deprecated section,\nwhich frees the URL but 404s external inbound links to a page that has been\nlive for years. Internal links were already updated; this covers the ones we\ndo not control.\n\nUses .htaccess rather than leaving a stub page behind, following the existing\n\"downloads was renamed to releases\" precedent in the same file: no orphan page\nin the nav tree, and the reader lands on the section rather than on a pointer\nto it. Matches both the extensionless and .html forms.\n\nIssued as a permanent (301) redirect. The fold-in is not going to be undone,\nand 301 is what consolidates the old URL\u0027s link equity onto the new section;\nthe surrounding rules only default to 302 because none of them ever specified.\n\nPins the target heading\u0027s anchor explicitly with {#...} instead of relying on\nkramdown\u0027s auto_ids. The generated id is identical today, but eight internal\nlinks and the redirect now depend on it, so it should not be a side effect of\nthe heading\u0027s wording.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "924768d174b70310f3f9118775345643083e6a1d",
      "tree": "9bf5560e0edb4c98932c06dc02a16b3ac6f00bb8",
      "parents": [
        "357d866a76b478ad65cde793cdd1cdc726d4d579"
      ],
      "author": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Thu Aug 27 10:02:52 2026 +0000"
      },
      "committer": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Thu Aug 27 10:02:52 2026 +0000"
      },
      "message": "Updates Maven site by Jenkins\n"
    },
    {
      "commit": "357d866a76b478ad65cde793cdd1cdc726d4d579",
      "tree": "f4e355e8836e904dd769e1ebe6ef68f5c881d66d",
      "parents": [
        "583acf30b6e131e3ca366c8d43eebf54b0cb4b12"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu Aug 27 11:53:57 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Aug 27 11:53:57 2026 +0200"
      },
      "message": "ci: show the Struts tag in the javadocs build name (#327)\n\nThe build history only showed the build number (e.g. #8), so there was no\nway to tell which STRUTS_TAG a run had built without opening it. Set\ncurrentBuild.displayName to \"#\u003cnumber\u003e \u003ctag\u003e\" at the start of the build.\n\n🤖 Generated by AI Assistant"
    },
    {
      "commit": "583acf30b6e131e3ca366c8d43eebf54b0cb4b12",
      "tree": "8c0446113dbc820ac9bf4440621fb5893a1e46f3",
      "parents": [
        "a4cb2e935b0c959b1eb244a044eb9dce90ee996d"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Aug 14 13:39:48 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 14 13:39:48 2026 +0200"
      },
      "message": "docs: add the one-time release setup steps to the guidelines (#325)\n\nThe guidelines listed what a release manager needs access to but never\nsaid how to configure any of it, which left the cwiki page \"One time\nsteps\" as the only description of the signing key, the KEYS file and\n~/.m2/settings.xml - and release:perform does not work without them.\n\nPort the parts that are still true and drop the rest. The KEYS file now\nlives in dist/release/struts rather than on people.apache.org, and the\nSSH key setup that page describes existed for scp deploys to a host that\nno longer exists.\n\nDeviate from the old page on credential handling: it stored the LDAP\npassword and the GPG passphrase in clear text in settings.xml. Point at\nmvn --encrypt-password and gpg-agent instead.\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "a4cb2e935b0c959b1eb244a044eb9dce90ee996d",
      "tree": "ea57878f61c66efed7ae10c1ac168e1d91472cb0",
      "parents": [
        "46c2fb2fdfcb3f2e948a007eca4e9bb83f1751b5"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Aug 14 13:27:30 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 14 13:27:30 2026 +0200"
      },
      "message": "docs: rewrite the release guidelines as the current release process (#324)\n\nThe Release Process section described a process that has not been run in\nyears: an Ant \"release\" target, Cactus tests, a test build posted to\nsvn.apache.org/struts/, and a release plan on wiki.apache.org. The only\nend-to-end description of how a release is actually made was the cwiki\npage \"Building Struts 2 - Normal release\", last revised in 2017, which\nis right about JIRA, the release plugin, Nexus and dist.apache.org and\nwrong about everything downstream from there.\n\nReplace it with the seven-phase process the 7.3.0 and 6.11.0 releases\nwere made with - prepare, cut, stage, vote, promote, publish, advisories\n- each with a gate that someone other than the release manager can\nverify, and with the commands needed at each step. Notably: releases are\ncut on a release/X.Y.Z-RC1 branch rather than on the line branch, the\nmaven-release-plugin takes no command-line flags now that they live in\nthe pom, the SCM tag prompt needs STRUTS_X_Y_Z typed by hand, and the\nsite update is a pull request rather than an svn commit to a production\ncheckout that no longer exists.\n\nDrop the Coding Conventions and Clarifications sections in favour of a\npointer to the coding standards page, which covers the same ground and\nis maintained.\n\nThis page is now the source of truth for the process; the cwiki pages\nwill be replaced with pointers to it.\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "46c2fb2fdfcb3f2e948a007eca4e9bb83f1751b5",
      "tree": "a3776c620ee9e51da8877101ff5959510fa55aca",
      "parents": [
        "2bfdab78b165016ae4b22469659de2833892501e"
      ],
      "author": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Fri Aug 14 07:43:30 2026 +0000"
      },
      "committer": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Fri Aug 14 07:43:30 2026 +0000"
      },
      "message": "Updates Maven site by Jenkins\n"
    },
    {
      "commit": "2bfdab78b165016ae4b22469659de2833892501e",
      "tree": "d808b8d9a691ef62f386cc9105fb259be426cfa1",
      "parents": [
        "53639ae498152be7c00a670f2796624aa3bd4e25"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri Aug 14 09:39:27 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 14 09:39:27 2026 +0200"
      },
      "message": "docs: announce security bulletins S2-070 to S2-074 (#323)\n\n* docs: announce security bulletins S2-070 to S2-074\n\nFive bulletins were published on the cwiki on 14 August 2026, covering\nCVE-2026-73631 through CVE-2026-73635. All five are fixed in 7.3.0, and\nthe three that also affect the 6.x line are fixed in 6.11.0.\n\nEach CVE gets its own dated entry so it can be linked individually, in\nthe S2-068/S2-069 form. All five share a date, so every anchor carries\nits bulletin number (a20260814-s2070 and onwards) rather than leaving\nthe first one to claim the bare date.\n\nOn the home page the security box now points at the whole batch rather\nthan a single bulletin, and S2-069 moves into the slot vacated by\nS2-068, which is a year old.\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: list S2-069 to S2-074 in the Prior Releases table\n\nAdds the five bulletins published today to every affected row, and\nbackfills S2-069, which was announced on 11 January 2026 but never\nreflected in the table.\n\nAffected ranges are taken from the bulletins themselves:\n\n- S2-070, S2-071: Struts 7.2.1 only\n- S2-072: 2.1.8-2.3.37, 2.5.0-2.5.33, 6.0.0-6.10.0, 7.0.0-7.2.1\n- S2-073: 6.0.0-6.10.0, 7.0.0-7.2.1 (no 2.5.x row is affected)\n- S2-074: 2.0.0-2.3.37, 2.5.0-2.5.33, 6.0.0-6.10.0, 7.0.0-7.2.1\n- S2-069: 2.0.0-2.3.37, 2.5.0-2.5.33, 6.0.0-6.1.0, so 6.1.1 and later\n  6.x rows stay untouched\n\nThe five rows that previously carried an empty Vulnerability cell\n(7.2.1, 6.10.0, 7.1.1, 6.9.0, 6.8.0) are now populated. Column padding\nis rewritten throughout because the widest cell grew.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: link every S2-070 to S2-074 announcement from the home page\n\nThe security box named five bulletins but pointed at a single\nannouncement anchor. Each bulletin now carries its own link, with a\nshort subject so the list says what each one covers.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "53639ae498152be7c00a670f2796624aa3bd4e25",
      "tree": "dcdf2767ae94906d11b60c5949018bc696be556a",
      "parents": [
        "7e558d15d2dc6044e72dd0cf468c47c76b07b442"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Tue Aug 11 14:10:19 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 11 14:10:19 2026 +0200"
      },
      "message": "docs: announce Struts 7.3.0 and 6.11.0 General Availability (#322)\n\nBoth releases were tagged on 1 August 2026 and their votes closed on\n11 August 2026. The site dates announcements by the tag date, matching\n7.2.1 (tagged 15 June, announced 30 June, listed as 15 June).\n\nBecause both releases share a tag date, the 6.11.0 entry uses the\ndisambiguated anchor a20260801-6110 so the two GA boxes on the home page\nlink to their own entries instead of both landing on 7.3.0.\n\nMinimum requirements are unchanged -- verified against the tags\u0027 poms:\n6.x stays on Java 8, 7.x stays on maven.compiler.release 17.\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "7e558d15d2dc6044e72dd0cf468c47c76b07b442",
      "tree": "57a58dfd68b9a18e4bb6d2632ad00242249ccff4",
      "parents": [
        "f9560de68b4719d98bba483b97667543e10f9366"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Tue Aug 11 13:01:59 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 11 13:01:59 2026 +0200"
      },
      "message": "docs: audit Struts 7.3.0 and 6.11.0 release notes against the documentation (#321)\n\n* docs: document Struts 7.3.0 multipart and upload-policy changes\n\nWW-5474: struts.multipart.maxFiles now counts uploaded files only, and the\nnew struts.multipart.maxParameterCount (default 256) limits normal fields.\nBoth limits are fail-closed and enforced identically by the jakarta and\njakarta-stream parsers.\n\nWW-5413: small uploads stay in memory; the temporary file is written lazily.\nDocument the new UploadedFile.getInputStream() / isMissing() default methods.\n\nWW-5659: lazy ${...} interceptor params resolve into a per-invocation\nUploadPolicy; an unresolved expression now rejects the upload. Document the\nacceptFile(UploadPolicy, ...) signature change and the WithLazyParams break.\n\nAlso correct the upload error-message keys: Struts 7.x uses the Commons\nFileUpload 2 exception names, Struts 6.x the 1.x ones.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document struts.validators.skipValidatorsOnConversionError\n\nWW-2934: an opt-in constant (default false) that skips a field\u0027s remaining\nvalidators once that field has a type conversion error, so the user no longer\nsees both a conversion error and a redundant validator error. The conversion\nfield validator itself is never skipped.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document @TypeConversion key derivation and ConversionRule.COLLECTION deprecation\n\nWW-3871: @TypeConversion accepts a bare property name in `key` for every\nConversionRule at class, method and field level — the rule prefix is derived.\nThe annotation is now also valid on fields (@Target METHOD, FIELD).\n\nWW-5656: ConversionRule.COLLECTION and the Collection_ prefix are deprecated\nsince 7.3.0 in favour of ConversionRule.ELEMENT / Element_.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document localized-text cache tuning and request-locale validation\n\nWW-5668: the AbstractLocalizedTextProvider caches are now size-bounded and\nconfigurable via struts.i18n.cacheType / struts.i18n.cacheMaxSize, and\nstruts.locale.validateRequestLocale (opt-in) restricts request-derived\nlocales to the JVM\u0027s available-locale set on the Dispatcher path.\n\nBoth constants ship in Struts 6.11.0 and 7.3.0.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document struts.csp.report.maxSize\n\nWW-5666: CspReportAction reads the submitted violation report up to a bounded\nlength, defaulting to 8192 characters and configurable via\nstruts.csp.report.maxSize (accepted range 1..1048576). Oversized reports are\ndiscarded and never reach processReport().\n\nShips in Struts 6.11.0 and 7.3.0.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document JSON plugin changes in Struts 7.3.0\n\nWW-5652: Java records are serialized by iterating record components, @JSON and\n@JSONFieldBridge target record components, and Optional serializes as its\ncontained value or null.\n\nWW-5641 / WW-5650: struts.json.writer / struts.json.reader overrides work\nagain (they were ignored in 7.2.x), and the interceptor obtains a fresh\nreader/writer per request — custom implementations must be prototype-scoped.\n\nWW-5666: struts.json.maxLength is enforced while reading, in fixed-size\nchunks, and line terminators are no longer stripped (also in 6.11.0).\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document @StrutsParameter enforcement on creator-bound REST body properties\n\nWW-5642: constructor-bound properties (Java records, @JsonCreator,\n@ConstructorProperties) bypassed the REST plugin\u0027s authorization wrapper up to\n7.2.1, so with struts.parameters.requireAnnotations enabled they were populated\nunchecked. Struts 7.3.0 authorizes them by path and redacts unauthorized\nvalues, which means actions relying on unannotated record binding must now\nauthorize those properties explicitly.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document specificity ordering of annotated wildcard actions\n\nWW-3784: @Action wildcard patterns were registered in arbitrary class-scan\norder, so a broad pattern could non-deterministically shadow a narrower one\nunder first-match-wins. Struts 7.3.0 sorts annotated action names\nmost-specific-first; XML mappings keep their declared order.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document Weld client-proxy recognition in the CDI plugin\n\nWW-5604: Struts resolved the target class behind Spring and Hibernate proxies\nbut not behind Weld client proxies, so members of normal-scoped CDI beans were\nevaluated against the proxy class in SecurityMemberAccess. The plugin now\nregisters CdiProxyService as struts.proxyService out of the box; Weld\ndetection activates only when Weld is on the classpath.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: simplify the creator-bound properties heading and its anchor\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: document the Log4j2 standardization completed in Struts 7.3.0\n\nWW-5620 replaced the remaining java.util.logging and SLF4J call sites\ninside the framework and dropped slf4j-api from struts2-core. Verified\nagainst the STRUTS_7_3_0 tag: the dependency is absent from core/pom.xml\n(it was declared optional in 7.2.1, so consumers see no classpath change)\nand STRUTS_6_11_0 still declares it.\n\nThe same change removed the container\u0027s Logger binding, so an\n@Inject java.util.logging.Logger in a container-managed bean no longer\nresolves -- flagged as a behaviour change.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "f9560de68b4719d98bba483b97667543e10f9366",
      "tree": "a906ad262246a33a1beeb9091753038255db2fd9",
      "parents": [
        "807f7bd8867831dca5b277cf8c7d487508a81a49"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Aug 03 16:19:42 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 03 16:19:42 2026 +0200"
      },
      "message": "docs: replace the removed XWork logging layer with Log4j2 on the Logging page (#320)\n\n* docs: replace the removed XWork logging layer with Log4j2 on the Logging page\n\nThe page documented com.opensymphony.xwork2.util.logging.LoggerFactory,\nextending LoggerFactory, and -Dxwork.loggerFactory. That layer was deprecated\nin Struts 2.5 and removed in 6.0.0: org/apache/struts2 (com/opensymphony)\nxwork2/util/logging has 12 files at STRUTS_2_5_33 and none from STRUTS_6_0_0\nonwards, and no source in the current tags reads xwork.loggerFactory. The\nexamples did not compile and the system property was silently ignored.\n\nDescribe how logging actually works instead: Log4j2 via log4j-api/log4j-core,\nconfigured with log4j2.xml, with the log4j-jcl / log4j-slf4j-impl bridges\ncovering third-party libraries.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* build: ignore vendor/ so bundler\u0027s default install path stays out of git\n\n`bundle install --path vendor/bundle` — the standard way to install this\nsite\u0027s gems without touching the system gem dir — drops ~29 gems into\nvendor/, which then shows up as untracked on every branch. .bundle and\nGemfile.lock are already ignored; vendor/ was the missing one.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "807f7bd8867831dca5b277cf8c7d487508a81a49",
      "tree": "6f066d3a1ccaaa41bfdbbc8b1a9c62f458ea007b",
      "parents": [
        "14856465c3e8cdf63c5e086df2b289ae6937634f"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 29 09:42:38 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 09:42:38 2026 +0200"
      },
      "message": "docs: document ModelDriven parameter binding and authorization (#319)\n\n* docs: document ModelDriven parameter binding and authorization\n\nAn action implementing ModelDriven makes its model the target of\n@StrutsParameter authorization, so the model\u0027s members are bindable\nwithout the annotation. This holds on every input channel — request\nparameters, JSON bodies and REST bodies — since they all resolve the\nauthorization target through the same authorizer.\n\nDocument it on the @StrutsParameter page (canonical), with short notes\nand cross-links from the Model Driven Interceptor and REST plugin pages,\nplus guidance to shape a model as a request DTO rather than a domain or\npersistence entity.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* Adds ToC\n\n* docs: correct version attribution for ModelDriven exemption\n\n@StrutsParameter was introduced in 6.4.0; the ModelDriven exemption\narrived separately in 7.0.0. The previous wording conflated the two and\nread as though the annotation itself were a 7.0.0 feature.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: drop 6.x reference from ModelDriven authorization note\n\n@StrutsParameter enforcement is supported from Struts 7.0.0; 6.x is not\na version the annotation\u0027s behavior should be characterised against.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* docs: add ModelDriven binding note to the Model Driven page\n\nThe conceptual Model Driven page is the likelier landing spot for\nsomeone learning the feature, but said only that Struts populates the\nmodel\u0027s fields — with no mention that this lifts the @StrutsParameter\nrequirement, and no DTO guidance. Adds the same short note and\ncross-link the other pages carry.\n\nAlso corrects the interface\u0027s package: it is org.apache.struts2\n.ModelDriven in 7.x, not com.opensymphony.xwork2.ModelDriven.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "14856465c3e8cdf63c5e086df2b289ae6937634f",
      "tree": "11650054d4f68877ea324b3f55de1d741c6a9c6d",
      "parents": [
        "329586567f016413eea2301f366b2fea5dbbeb96"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 29 09:04:41 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 09:04:41 2026 +0200"
      },
      "message": "docs: add secure-usage guidance on trust state to Chaining Interceptor (#318)\n\nAction chaining populates the target action implicitly from the value\nstack. Document the design-level guidance that follows from that: keep\nauthorization, trust, identity and approval state out of the chain and\nre-derive it in the target action, prefer avoiding chaining, and narrow\nwhat is copied via Unchainable or the includes/excludes parameters.\n\nCross-links the \"Where authorization applies\" overview on the\n@StrutsParameter page.\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "329586567f016413eea2301f366b2fea5dbbeb96",
      "tree": "307d2d3525685e809ca2016aef3ecf128c4b953e",
      "parents": [
        "f5761f8ee49c3dc22e7b16022278e5bd0b8ae54f"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Jul 25 09:28:12 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jul 25 09:28:12 2026 +0200"
      },
      "message": "fix: point /announce.html at the newest announce-YYYY page (#317)\n\nThe redirect was hardcoded to /announce-2024.html, so it kept sending\nvisitors to the 2024 announcements even though 2025 and 2026 pages exist.\n\nAdd empty front matter to source/.htaccess so Jekyll renders Liquid in it,\nand resolve the target from the newest announce-* page at build time. No\nmanual update is needed when a new year file is added; CLAUDE.md and the\nannouncing-struts-release skill are updated to drop that step.\n\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "f5761f8ee49c3dc22e7b16022278e5bd0b8ae54f",
      "tree": "ec7278345a6e76b22c3322d6ad315ccc0057d7d4",
      "parents": [
        "1abc30338b7f06f728a204ec043cbdf6c6bc1fe7"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sat Jul 25 09:25:28 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jul 25 09:25:28 2026 +0200"
      },
      "message": "docs: JSON input parameter filtering \u0026 scalar-collection authorization (Struts 7.3.0) (#316)\n\n* docs: document JSON input parameter filtering (Struts 7.3.0)\n\nJSON population now applies the same name/value acceptability controls\nas the Parameters Interceptor (WW-4858, apache/struts#1773):\n\n- Always-on: framework-wide accepted/excluded name patterns, param-name\n  max length (paramNameMaxLength, default 100), ParameterNameAware /\n  ParameterValueAware callbacks, @StrutsParameter authorization.\n- Opt-in: acceptedValuePatterns / excludedValuePatterns and\n  applyPropertyFiltersToInput (reuse excludeProperties/includeProperties\n  on input).\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: clarify @StrutsParameter depth\u003d1 on getters for primitive collections (JSON/REST)\n\n@StrutsParameter authorization on the JSON path exists since 7.2.0; PRs\n#1773/#1784 align its logic with ParametersInterceptor. Extend the\ncollections example to make clear that populating a collection of simple\ntypes element by element (mySelection[0]) — as JSON/REST payloads do —\nrequires @StrutsParameter(depth \u003d 1) on the getter, not on the setter.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "1abc30338b7f06f728a204ec043cbdf6c6bc1fe7",
      "tree": "266f797a16d475ce84da67aa77430578b396609c",
      "parents": [
        "0c49b6de60947a7ed3b5a1a0c716623134cb9cb3"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Mon Jul 06 15:34:13 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 06 15:34:13 2026 +0200"
      },
      "message": "WW-5640 docs: document WebJars support (Struts 7.3.0) (#315)\n\n* WW-5640 docs: add webjar tag reference page\n\nDocument the new \u003cs:webjar\u003e tag (and \u003c@s.webjar\u003e macro) that resolves\nversion-less WebJar resource paths to servable URLs, introduced in\nStruts 7.3.0. Pulls description/attributes from the released source and\nlinks the Static Content serving pipeline. Lists the tag under Other\nTags in the tag reference index.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* WW-5640 docs: document WebJars support in static content\n\nAdd a WebJars support section to the Static Content guide covering the\nnew /static/webjars/** serving pipeline, version-less resolution, the\nstruts.webjars.enabled and struts.webjars.allowlist constants, the\nfail-closed security constraints, and the WebJarUrlProvider extension\nseam. Introduced in Struts 7.3.0.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "0c49b6de60947a7ed3b5a1a0c716623134cb9cb3",
      "tree": "a6a313b2905eda3787ab2c98a30a556323c6b773",
      "parents": [
        "e87b4d3ec920fc4e18302833d2f2cfdf3147c8cc"
      ],
      "author": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Wed Jul 01 12:45:50 2026 +0000"
      },
      "committer": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Wed Jul 01 12:45:50 2026 +0000"
      },
      "message": "Updates Maven site by Jenkins\n"
    },
    {
      "commit": "e87b4d3ec920fc4e18302833d2f2cfdf3147c8cc",
      "tree": "702be92ec5e8bbcb0a9d84b861ae8b11213d8639",
      "parents": [
        "cfd71366713910173e5e3c1af52ff5436e43cb94"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 01 14:37:47 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 01 14:37:47 2026 +0200"
      },
      "message": "ci: publish only the menu-linked Maven site modules, flattened (#314)\n\nThe struts reactor stages module sites nested by POM inheritance\n(struts2-bom/struts2-parent/struts2-core/...), which does not match the\n/maven/... links in the website menu, so those links 404. Instead of moving\nthe whole staged tree, publish only what the menu references: the top-level\naggregate site at the root, plus struts2-core and struts2-plugins flattened\nto /maven/\u003cmodule\u003e/. Each module site is self-contained and struts2-plugins\ncarries its submodule sites, so moving whole directories preserves their\nlinks. This also drops the unreferenced modules (jakarta, apps, assembly)\nand the bom/parent scaffolding.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "cfd71366713910173e5e3c1af52ff5436e43cb94",
      "tree": "0420a733c2cdaceb78294c45155541492ebd9f84",
      "parents": [
        "aae2fb3a5b289b4bae389150bc1aa17640409938"
      ],
      "author": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Wed Jul 01 12:12:19 2026 +0000"
      },
      "committer": {
        "name": "jenkins",
        "email": "builds@apache.org",
        "time": "Wed Jul 01 12:12:19 2026 +0000"
      },
      "message": "Updates Maven site by Jenkins\n"
    },
    {
      "commit": "aae2fb3a5b289b4bae389150bc1aa17640409938",
      "tree": "4309b2815950b8311d611ba9b4aad78380e9c959",
      "parents": [
        "a9c78aed7a8546bd697840d3a69b8cf98d02ae4d"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 01 13:53:11 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 01 13:53:11 2026 +0200"
      },
      "message": "ci: check out asf/main explicitly in javadocs publish stage (#313)\n\nThe publish stage failed with \u0027main matched multiple (2) remote tracking\nbranches\u0027: the Pipeline-from-SCM checkout leaves an origin/main, and we add\nan asf remote that also has main, so a bare \u0027git checkout main\u0027 is ambiguous\nand git refuses. Use \u0027git checkout -B main asf/main\u0027 to pin the intended\nremote; this also makes the follow-up \u0027git pull asf main\u0027 redundant, so it\nis dropped.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "a9c78aed7a8546bd697840d3a69b8cf98d02ae4d",
      "tree": "82b62277811c34e56829ccd367cc736c5309ea1e",
      "parents": [
        "2ad559b1a73990a2f1d19321f5543d1ea19a8b02"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 01 12:12:30 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 01 12:12:30 2026 +0200"
      },
      "message": "ci: skip OWASP dependency-check report in javadocs site build (#312)\n\nThe site:site aggregate report ran dependency-check-maven, which downloads\nthe full NVD CVE database (~360k records) with no API key and blew the\n90-minute timeout (build ABORTED at ~17%). The OWASP report is not needed\nfor the published Maven site, so skip it with -Ddependency-check.skip\u003dtrue.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "2ad559b1a73990a2f1d19321f5543d1ea19a8b02",
      "tree": "78a675617af394d9d7d53bd0a8943345270a62dc",
      "parents": [
        "b57b82a4928a5010888ec4493fec22bf60344eb6"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 01 09:55:40 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 01 09:55:40 2026 +0200"
      },
      "message": "ci: skip staging site build when a PR changes no site files (#311)\n\nThe Struts-site multibranch job rebuilt Jekyll and pushed to asf-staging\non every PR, even PRs that touch only CI/docs and leave source/ untouched,\nproducing an identical staged site. Add a \u0027Check for site changes\u0027 stage\nthat diffs a PR against its target branch and sets SITE_CHANGED; gate the\nbuild, deploy, and PR-comment stages on it. Branch builds (main) always\nrebuild. Skipped stages still report success, so any required check stays\ngreen.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "b57b82a4928a5010888ec4493fec22bf60344eb6",
      "tree": "4fc2a71b38adcc64b7df0eb9a9c6b111c89afdc7",
      "parents": [
        "9bf4cca7858f8d4a760ae5ad4defc255faa7c3c5"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 01 09:55:26 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 01 09:55:26 2026 +0200"
      },
      "message": "ci: provision maven and jdk 17 via tools block in javadocs pipeline (#310)\n\nThe first run failed with \u0027mvn: not found\u0027 (exit 127): MAVEN_3_LATEST_HOME\nis not set on the git-websites/websites2 agent, so prepending it to PATH\nadded nothing. Replace the PATH hack with a declarative tools block\n(maven \u0027maven_3_latest\u0027, jdk \u0027jdk_17_latest\u0027), matching the apache/struts\nbuild. Struts 7 also requires JDK 17, which the block now supplies.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "9bf4cca7858f8d4a760ae5ad4defc255faa7c3c5",
      "tree": "324cec2c358ea0df4b028c44da52fbfdc88e88fe",
      "parents": [
        "bfed245a4beb6532aadb78f16b4e3e4a981d17fa"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 01 08:57:33 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 01 08:57:33 2026 +0200"
      },
      "message": "ci: convert Struts-site-javadocs job to a declarative pipeline (#309)\n\n* docs: add design spec for javadocs Jenkins pipeline conversion\n\nConverts the shell-based Struts-site-javadocs freestyle job into a\ndeclarative Jenkins pipeline (Jenkinsfile.javadocs), mirroring the\nexisting root Jenkinsfile conventions. Two intended deviations: use\nplain `mvn` instead of `./mvnw`, and push via the explicit `asf`\nremote.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: add implementation plan for javadocs Jenkins pipeline\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* ci: add declarative pipeline for the javadocs job\n\nConverts the shell-based Struts-site-javadocs freestyle job into\nJenkinsfile.javadocs. Builds Struts with plain `mvn` and publishes the\nstaged Maven site into source/maven on main via the asf remote.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "bfed245a4beb6532aadb78f16b4e3e4a981d17fa",
      "tree": "2c4cdbc69d520dd9813d1077ca63e101c885bb89",
      "parents": [
        "cff3eb1551f8e82bfb4b514f5a659337e18bb895"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Jul 01 07:49:07 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 01 07:49:07 2026 +0200"
      },
      "message": "WW-5626 docs: clarify @StrutsParameter depth for collections (#308)\n\nExplain how the `depth` parameter is counted (each property access or\ncollection/map index is one level) and correct the collection example to\nuse `depth \u003d 2` instead of `depth \u003d 1` — indexing into the collection is\nitself a level, so reaching an element\u0027s property needs depth 2 even for\nflat POJOs. Also note that JSON/REST payloads populating collection\nelements require the getter to be annotated, not just the setter.\n\nReported on the user list against 7.2.1 by Markus (flyingfischer.ch).\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "cff3eb1551f8e82bfb4b514f5a659337e18bb895",
      "tree": "0099aa04e686f2e0d0125636166222a6375b0343",
      "parents": [
        "0c406707cc1f6b3d4f151ecf1c70fa3d2663e0d3"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Tue Jun 30 07:56:28 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 30 07:56:28 2026 +0200"
      },
      "message": "docs: put the [ANN] email in the PR description in announcing-struts-release skill (#307)\n\nInstead of outputting the [ANN] email to the chat console, the skill now\nplaces it in the draft PR\u0027s description (fenced block under an \"## [ANN] email\"\nheading) so the release manager can copy it verbatim after merge. The email is\nstill never committed to the repo. Reorders the workflow to draft the email\nbefore opening the PR, and updates the overview, template heading, and the\ncommon-mistakes note to match.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "0c406707cc1f6b3d4f151ecf1c70fa3d2663e0d3",
      "tree": "8c2bc438efea1b721e82c4227f739bab35e68880",
      "parents": [
        "9fe357d0f25302ce437e8a508c9a021282e8dd19"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Tue Jun 30 07:56:07 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 30 07:56:07 2026 +0200"
      },
      "message": "docs: announce Apache Struts 7.2.1 GA release (#306)\n\nAdd the 7.2.1 General Availability announcement, bump the 7.x release\nvariables in _config.yml, point the homepage GA box to announce-2026,\nand move the superseded 7.1.1 release into Prior Releases.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "9fe357d0f25302ce437e8a508c9a021282e8dd19",
      "tree": "1cf5771b38bc9d92e5db8696b6a4777cfcec760a",
      "parents": [
        "1c4bcacb3699a4952c4406f129976af4906a6583"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Jun 14 20:32:22 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jun 14 20:32:22 2026 +0200"
      },
      "message": "docs: add breaking-change detection to documenting-struts-release skill (#305)\n\nBreaking changes were the skill\u0027s biggest gap: a baseline subagent test showed\nagents missed backward-incompatible items because they (a) only scanned New\nFeature/Improvement, and (b) dropped dependency bumps as \u0027internal\u0027 — exactly\nwhere breakage hides (OGNL, commons-fileupload method renames, UIBean field\nvisibility).\n\nAdds a dedicated breaking-changes pass: a keyword shortlist over ALL issue types,\na 6-point checklist (changed default, new enforcement, removed/narrowed API,\nraised minimum requirement, breaking dependency bump, output/encoding change),\nnet-delta dependency verification against the tag POM, and migration-note output.\nRe-verified with a with-skill subagent test (correctly found the 7.2.0 breaking\nchanges and ruled out non-breaking items).\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "1c4bcacb3699a4952c4406f129976af4906a6583",
      "tree": "994f2549fdb9f48ae543e4403866146c62360286",
      "parents": [
        "29a1090fdee3c8b3fb448ca6f2627fe7f6755e50"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Jun 14 20:16:42 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jun 14 20:16:42 2026 +0200"
      },
      "message": "docs: add documenting-struts-release skill (#304)\n\nCapture the repeatable content-audit procedure for a new Struts release:\npull the itemized JIRA release notes, check existing coverage first (don\u0027t\nre-document), map each item to its page under core-developers/tag-developers/\nplugins, verify constant names/defaults against the STRUTS_X_Y_Z tag source\n(not JIRA proposals), document only real gaps, and keep announcement mechanics\nin announcing-struts-release.\n\nDerived from the 7.2.0 content audit (PR #303) and validated with a\nbaseline/with-skill subagent test.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "29a1090fdee3c8b3fb448ca6f2627fe7f6755e50",
      "tree": "7bcaf3c08186083f89bc15b3178fa9a7266c889d",
      "parents": [
        "471963ff40207e9e908dc06b1506090f71716ee7"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Sun Jun 14 19:56:41 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jun 14 19:56:41 2026 +0200"
      },
      "message": "docs: document Struts 7.2.0 changes (@StrutsParameter authorization, JSON limits) (#303)\n\n* docs: add 7.2.0 content audit design spec\n\nCaptures the documentation gap analysis for the Struts 7.2.0 release notes:\nthe @StrutsParameter authorization expansion (ChainingInterceptor,\nCookieInterceptor, JSON/REST) and the new JSON deserialization limits.\nAnnouncement mechanics are out of scope.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: add 7.2.0 content audit implementation plan\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: document chaining interceptor @StrutsParameter enforcement (WW-5631)\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: document cookie interceptor @StrutsParameter authorization (WW-5627)\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: make @StrutsParameter page the authorization hub (WW-5626/5631/5627)\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: document JSON deserialization limits and per-property authorization (WW-5618/5626)\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n* docs: note AuthorizationAwareContentTypeHandler in REST plugin (WW-5626)\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "471963ff40207e9e908dc06b1506090f71716ee7",
      "tree": "f015ec5405b0c7829115b58cf2d9f2df75be1df5",
      "parents": [
        "7ac165beff451e3c9b467ff2fd21bb934d39fb32"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri May 29 14:40:28 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri May 29 14:40:28 2026 +0200"
      },
      "message": "docs: add announcing-struts-release skill (#302)\n\nCapture the repeatable release-announcement procedure as a Claude Code\nskill: add the announce-YYYY entry, bump the correct 6.x/7.x version\nvariables in _config.yml, the conditional index.html year-link edit,\nmove the superseded version into the Prior Releases table, open the\ndraft PR, and draft the [ANN] user-list email (not committed).\n\nDerived from the 6.10.0 release and modeled on PR #292.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "7ac165beff451e3c9b467ff2fd21bb934d39fb32",
      "tree": "c46b97897356c84722bfdb60ac40b2dd435f544e",
      "parents": [
        "c885fb5d9f8dadca258d86e3785a2902fe7311c0"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri May 29 14:28:18 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri May 29 14:28:18 2026 +0200"
      },
      "message": "docs: announce Apache Struts 6.10.0 GA release (#301)\n\nAdd 6.10.0 General Availability announcement to announce-2026, bump the\n6.x release variables in _config.yml (which also updates the homepage GA\nbox), and move the superseded 6.9.0 into the Prior Releases table.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "c885fb5d9f8dadca258d86e3785a2902fe7311c0",
      "tree": "e5d56cef1e8630feb2ce513db17cdc79ba1525e4",
      "parents": [
        "79a4cb8c1b9db664201189ae12c0507cd954ec9b"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed May 27 07:37:25 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed May 27 07:37:25 2026 +0200"
      },
      "message": "docs(security): links security reporting with security guideline (#300)"
    },
    {
      "commit": "79a4cb8c1b9db664201189ae12c0507cd954ec9b",
      "tree": "c0cd3e4769a9669dcf144893fe62e05505c8614b",
      "parents": [
        "13ebe2d28cbe9c8ce89aaecf55468f582fde6c9a"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Fri May 22 06:48:03 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri May 22 06:48:03 2026 +0200"
      },
      "message": "security: updates the page and links to SECURITY.md (#299)"
    },
    {
      "commit": "13ebe2d28cbe9c8ce89aaecf55468f582fde6c9a",
      "tree": "93aae6c6760aa18d282306d528ef722cbbcb6c62",
      "parents": [
        "d7885fc9db1155fc98e00c628f7e0591881d8e66"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Thu May 14 14:03:52 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu May 14 14:03:52 2026 +0200"
      },
      "message": "docs: add EOL versions page and cross-link from related pages (#291)\n\n* docs: add EOL versions page and cross-link from related pages\n\n- Add source/eol-versions.md — dedicated page explaining what EOL means,\n  listing EOL branches, and linking to commercial support options (neutral wording)\n- Update index.html — generalize the Struts 2.5.x EOL card to cover all EOL\n  versions and link to the new page\n- Update download.md — add note in Prior Releases section pointing to eol-versions\n- Update releases.md — add note before the Prior Releases table and in the\n  Older Releases bullet\n- Update commercial-support.md — clarify HeroDevs entry description and update date\n\nCo-Authored-By: Claude Sonnet 4.6 \u003cnoreply@anthropic.com\u003e\n\n* docs: add End-of-Life Versions to Support navigation menu\n\nCo-Authored-By: Claude Sonnet 4.6 \u003cnoreply@anthropic.com\u003e\n\n* chore: trigger staging build\n\nCo-Authored-By: Claude Opus 4.7 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Sonnet 4.6 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "d7885fc9db1155fc98e00c628f7e0591881d8e66",
      "tree": "8d61191dfba85170a1fa1f55212bbc43b3e2e052",
      "parents": [
        "f5b47b3f594f9641c252539e2d22c5633f557601"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Apr 29 08:43:38 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 29 08:43:38 2026 +0200"
      },
      "message": "docs: add 6.8.0 to Prior Releases and document the dependency (#298)\n\n* docs: simplify IDEA plugin install to a single Marketplace button\n\nDrop the surrounding card mock-up and keep only the \u0027Get from\nMarketplace\u0027 button — the card without the live download/rating data\ndidn\u0027t add value.\n\n* docs: add 6.8.0 to Prior Releases and document the dependency\n\nMove 6.8.0 into the Prior Releases table on releases.md now that\n6.9.0 supersedes it. Document in README.md and CLAUDE.md that\nreleases.md must be updated alongside _config.yml and the yearly\nannouncement file when preparing a new release."
    },
    {
      "commit": "f5b47b3f594f9641c252539e2d22c5633f557601",
      "tree": "a375dcbfaef21c596928c209995b4e2d431bcc9c",
      "parents": [
        "bc0d98dd896343f871c2c6e1984b130d846af6dd"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Apr 29 08:26:26 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 29 08:26:26 2026 +0200"
      },
      "message": "docs: simplify IDEA plugin install to a single Marketplace button (#297)\n\nDrop the surrounding card mock-up and keep only the \u0027Get from\nMarketplace\u0027 button — the card without the live download/rating data\ndidn\u0027t add value."
    },
    {
      "commit": "bc0d98dd896343f871c2c6e1984b130d846af6dd",
      "tree": "bd7c2fa92b35647e71a7ff0edab10f4ef658552d",
      "parents": [
        "11fdba415d3ccc42802a4bb86f9cff44d4611946"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Apr 29 08:21:32 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 29 08:21:32 2026 +0200"
      },
      "message": "docs: fix broken rendering of IDEA plugin Marketplace card (#296)\n\nThe Kramdown parser breaks when block-level elements (div, p) are\nnested inside an inline anchor — the closing \u003c/a\u003e ends up rendered\nas literal text. Restructure the card so the outer wrapper is a div\nand only the \u0027Get from Marketplace\u0027 button is an anchor."
    },
    {
      "commit": "11fdba415d3ccc42802a4bb86f9cff44d4611946",
      "tree": "288e1c6bf87eb42863b0b5467bc4b05aefe462b0",
      "parents": [
        "4aee9d9d5393ff0e5d790b00549cfd139afc25f5"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Apr 29 08:13:16 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 29 08:13:16 2026 +0200"
      },
      "message": "docs: replace blocked Marketplace iframes with static card (#295)\n\nThe JetBrains Marketplace embeddable widgets (iframe and script\nvariants) both load from plugins.jetbrains.com, which is not allowed\nby the ASF site CSP (frame-src/script-src). Replace them with a\nself-contained static card linking to the Marketplace listing."
    },
    {
      "commit": "4aee9d9d5393ff0e5d790b00549cfd139afc25f5",
      "tree": "8cb0f652537ea3b2e038393130ac25a724e4c68c",
      "parents": [
        "860646af6d4898c3ebdd822e67bb6e5af8e10c20"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Wed Apr 29 08:03:59 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 29 08:03:59 2026 +0200"
      },
      "message": "docs: link IDEA plugin page to Marketplace and GitHub releases (#294)\n\nReplace the outdated Version notes section with embedded JetBrains\nMarketplace card/install widget and a pointer to the GitHub releases\npage as the single source of truth for release notes."
    },
    {
      "commit": "860646af6d4898c3ebdd822e67bb6e5af8e10c20",
      "tree": "82d70cf54d71d8aff0760073760f3e80675a5cb4",
      "parents": [
        "61574deef06fd2ad05b3eaa712b56fe9cffcb62b"
      ],
      "author": {
        "name": "Lukasz Lenart",
        "email": "lukaszlenart@apache.org",
        "time": "Tue Apr 28 13:37:00 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 28 13:37:00 2026 +0200"
      },
      "message": "Remove stale Maven site snapshot from source/ (#293)\n\nThe source/maven/ tree was a one-off snapshot from April 2020 (commit\n1e7942f2a) pinned at Struts 2.6-SNAPSHOT. Each Jekyll publish from main\ncopied it into output/maven/ on asf-site, overwriting the fresh content\nthat the Jenkins JavaDocs job stages there and reverting the displayed\nversion back to 2.6-SNAPSHOT.\n\nThe Jenkins job is the sole source of truth for output/maven/ on\nasf-site, so this directory should not exist in main."
    }
  ],
  "next": "61574deef06fd2ad05b3eaa712b56fe9cffcb62b"
}
