)]}'
{
  "log": [
    {
      "commit": "d6b47e7f447d9e07a7a6c67ea0a6e778c410d0e9",
      "tree": "cb8ee83ebf418c14887c80799877b7d8cce5090f",
      "parents": [
        "664dedb62474eb1f5890732c7b5ec33f582dddad"
      ],
      "author": {
        "name": "Brian Olsen",
        "email": "brian_olsen2@comcast.com",
        "time": "Thu Oct 15 15:51:17 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 15 15:51:17 2026 -0600"
      },
      "message": "nexthop: reject a bare #include in strategies.yaml (#13837)\n\n* nexthop: reject a bare #include in strategies.yaml\n\nA \u0027#include\u0027 with no file name built a std::string from a null\npointer, which crashes with libc++ and throws an unhelpful\nbasic_string error with libstdc++. Reject it with a clear message,\nand keep the nested load error when an included file fails.\n\n* replace strtok_r calls with string_view operations for include parsing"
    },
    {
      "commit": "664dedb62474eb1f5890732c7b5ec33f582dddad",
      "tree": "30329ab262fcf5ffb495ee755f75070a0039f244",
      "parents": [
        "c26c091e8baaade7ee6f16bd0b562b0828eb203b"
      ],
      "author": {
        "name": "Giulio Savini",
        "email": "giuliosavini@proton.me",
        "time": "Thu Oct 15 11:31:15 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 15 11:31:15 2026 +0200"
      },
      "message": "ArgParser: resolve declared env vars into missing option values (#13825)\n\n* ArgParser: resolve declared env vars into missing option values\n\nA command or option can declare an environment variable, but nothing\never read it except src/tscore/unit_tests/test_ArgParser.cc. The value\nwas captured into ArgumentData::env() when the flag was typed with an\nexplicit value, but could never fill one that was left out, so\nTS_RECORD_YAML (traffic_ctl config get -c) and TS_DEBUG_TAGS\n(traffic_ctl server debug enable --tags) were decorative.\n\nResolve the variable during parsing instead, with precedence typed\nvalue \u003e environment variable \u003e declared default, so callers reading\nthrough ArgumentData::value()/at() need no special handling. This\ncovers a fixed arity option missing its value, AT_MOST_ONE_ARG_N\ntaking no value, and MORE_THAN_ONE_ARG_N collecting none. The variable\nis only consulted when the flag is actually written, never to activate\none that was never typed.\n\nFixes: #13588\n\n* ArgParser: refuse an empty token instead of env-filling it\n\nA fixed-arity option\u0027s missing-value check treated an empty command-\nline token the same as an absent one, so it was silently filled from\nthe declared environment variable without ever advancing past it.\nThe empty token then stayed in args and the enclosing command read it\nas a positional argument (e.g. traffic_ctl config get --run-root \"\").\n\nOnly a genuinely absent token (past the end of args) should fall back\nto the variable; an empty token the caller actually typed is a value\nand must be refused, matching the check append_option_data() already\nmakes for AT_MOST_ONE_ARG_N.\n\nAdds the two regression cases from review, plus three more covering\ngaps the review pointed out: a command\u0027s own declared variable, that\nan option is never activated by its variable alone, and that a typed\nvalue wins outright rather than just by count.\n\n* ArgParser: defer env fallback until every occurrence is seen\n\nThe previous fix filled a missing value from the declared variable as\nsoon as one bare occurrence was parsed, so a repeated option could mix\na bare occurrence with one that had a real value: \"-t dns -t\" silently\nkept \"dns\" instead of reporting the same missing-value error the bare\n\"-t\" would have been on its own, and the order the two spellings\nappeared in could change the outcome.\n\nResolve the variable only after every occurrence of the command or\noption has been parsed, tracking per key whether any occurrence had a\nvalue and whether any was bare, outside the option\u0027s own Arguments\nentry so a later occurrence cannot erase what an earlier one saw. The\nvariable now fills a value only when every occurrence is bare; a bare\noccurrence next to a valued one, in either spelling and either order,\nis the same usage error it would be without a variable at all. A line\nwith no bare occurrence, including the existing last-one-wins behaviour\nfor a fixed-arity repeat, is untouched.\n\nAlso restricts the fallback for a fixed arity above one to a fully bare\noccurrence: a partial set is always a usage error, matching the base\nbehaviour has always had and review comments on PR #13825.\n\nAdds the deferred TS_RECORD_YAML AuTest coverage from the review, and\nunit test coverage for the repeated-option and partial-arity cases.\n\nFixes: #13588\n\n* ArgParser: only defer a bare value when the variable is set now\n\nTwo bugs let a token after a bare occurrence run before the variable\nwas ever consulted, both because the deferral itself fired too eagerly\nor too late:\n\n- A missing value was deferred whenever the option merely declared a\n  variable, regardless of whether it was currently set. With\n  TS_RUNROOT unset, \"traffic_ctl --run-root -h\" exited 0 with the help\n  text instead of the usage error base reports, because deferring let\n  the scan reach \"-h\" before anything checked the variable was empty.\n  Resolve the variable\u0027s current value before calling handle_args(),\n  and defer only when it is non-empty; an unset variable now reports\n  the same immediate error as no variable at all.\n\n- A bare occurrence next to a valued one was only caught by the\n  end-of-scan resolution loop, so a token after the conflicting pair\n  (e.g. \"--help\") could still run first. Detect the conflict the\n  moment the second, contradicting occurrence is parsed instead,\n  in both spellings, so nothing written afterwards gets a chance to\n  run before the usage error does.\n\nAT_MOST_ONE_ARG_N resolves immediately in handle_args() rather than\nthrough this deferred path, since repetition of it is already refused\noutright elsewhere and a missing value is valid input for it on its\nown either way; apply_env_fallback() is gone with it; the remaining\nfill is a few lines inline.\n\nFixes: #13588"
    },
    {
      "commit": "c26c091e8baaade7ee6f16bd0b562b0828eb203b",
      "tree": "3da1d1417295ed3d4adc735a2f5a1c62a9fc2950",
      "parents": [
        "55cde6d0d6742e55e64a3440b59dae0b924e701b"
      ],
      "author": {
        "name": "Damian Meden",
        "email": "dmeden@apache.org",
        "time": "Thu Oct 15 10:15:05 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 15 10:15:05 2026 +0200"
      },
      "message": "Add severity-aware exit codes to traffic_ctl (#13032)\n\n* traffic_ctl: severity-aware exit codes\n\ntraffic_ctl exits 2 for any server error, so a script cannot tell a\nwarning such as \"Server already draining.\" from a real failure.\n\nThe JSONRPC server now sends the severity of an annotation when the\nhandler set one, and traffic_ctl grades handler failures against a new\n--error-level option (default: error). An annotation without a severity\ncounts as an error, so every existing failure keeps exiting 2; the\ndrain handlers now report \"already in that state\" as a warning.\n\nThe grading applies to every command that decodes the response,\nincluding --format json, config reload and config status.\n\n* traffic_ctl: do not use std::ranges\n\nThe ubuntu CI build compiles with clang 12 against a libstdc++ whose\n\u003cranges\u003e it cannot use, and core code does not use std::ranges\nanywhere else. Use std::max_element with a comparator instead.\n\n* traffic_ctl: refuse a repeated --error-level\n\nArgParser keeps only the last value of a fixed-arity option repeated\nwith a space, so an invalid earlier --error-level was never checked.\nDeclare it as taking at most one value: ArgParser then refuses any\nrepetition, and a missing value is reported instead of falling back to\nthe default.\n\n* traffic_ctl: do not replace tags on a lookup error\n\nserver debug enable --append reads the current debug tags and sends\ncurrent|new. A failed read was ignored: the error was neither printed\nnor graded, and the new tags were set on their own, replacing the\ncurrent ones. Report the error and set nothing. The command fails even\nbelow --error-level, since the requested change was never made.\n\n* traffic_ctl: exit 75 when --append cannot run\n\nWhen the tag lookup of server debug --append fails with an error below\n--error-level nothing is set, so exiting 0 would report success for a\nchange that was never made. Exit 75 (not done, retry) instead, as\nconfig reload --monitor does when it cannot see how a reload ended. At\nor above the level the command still exits 2.\n\n* traffic_ctl: exit 75 when a needed request fails\n\nconfig reset, metric monitor and config reload --show-details exited\n0 when a request they depend on failed below --error-level, so a\nscript took the command as done. They now exit 75, like config reload\n--monitor and server debug enable --append, through one helper.\n\nDocument that levels below warn act like warn against traffic_server,\ncorrect the handler guide and the upgrade notes, and tighten tests\nthat passed with a decoder branch removed or a fall-through.\n\n* doc: link --error-level to the severity section\n\nThe option describes the severity field, so point it at the section\nthat defines it rather than the top of the JSONRPC error page.\n\n* traffic_ctl: one list of --error-level names\n\nparse_error_level now compares with ts::iequals, the tree\u0027s helper\nfor case-insensitive equality. The help text and both error messages\nprint the accepted values built from Severity_Names, so they cannot\ndrift from what the parser accepts."
    },
    {
      "commit": "55cde6d0d6742e55e64a3440b59dae0b924e701b",
      "tree": "e315245946ed8b60cc146ec6089777df74c672a9",
      "parents": [
        "1d232a3d4edd626decfd2b03a403e2a22763ebb6"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Wed Oct 14 10:46:39 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 14 10:46:39 2026 -0700"
      },
      "message": "Fix the flaky origin check in http2_rst_stream (#13833)\n\nThe two client RST_STREAM cases required that the origin never log\nRST_STREAM. On a loaded machine ATS can forward the request before the\nclient\u0027s reset arrives, then answer the origin\u0027s DATA on the closed stream\nwith RST_STREAM(NO_ERROR) after the origin has finished. The check now\nfails only when a reset reaches an origin stream that is still open."
    },
    {
      "commit": "1d232a3d4edd626decfd2b03a403e2a22763ebb6",
      "tree": "6545bb3b48618c9fa99485a07284bf8da2587656",
      "parents": [
        "4de94cd962d67291c72d2c402b07c7e9cfd4a092"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Wed Oct 14 11:06:56 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 14 11:06:56 2026 -0500"
      },
      "message": "Fix TLS callback retries after paused hooks (#13799)\n\nWhen a plugin pauses the TLS handshake in a ClientHello or certificate\nhook and later reenables it, OpenSSL calls the same callback again.  By\nthen the callback\u0027s work and its hooks have already run, and the hook\nstate has moved on to the next stage.  The callbacks did not check for\nthis and repeated their work:\n\n1. ssl_cert_callback() selected the certificate again, which replaced\n   any SSL_CTX the plugin had chosen.  It also dispatched the\n   verify-client hooks with TS_EVENT_SSL_CERT.  With a verify-client\n   plugin installed, even clients that sent no certificate then stalled\n   until they timed out.\n\n2. ssl_client_hello_callback() dispatched again, so servername hooks\n   received TS_EVENT_SSL_CLIENT_HELLO.  The servername callback then\n   started the cert hooks with TS_EVENT_SSL_SERVERNAME and ignored their\n   pause, so certificate selection was skipped.\n\nBoth callbacks now skip a hook phase that has already completed.  On a\nretry, the certificate callback still applies the per-SNI client CA\ncertificates and session-ticket settings.  Skipping a completed phase\ndoes not skip the rejection of a renegotiation that is not allowed.  A\nrenegotiation starts a new handshake, so it still runs the SNI actions,\nand its certificate lookup behaves as before.  The callbacks get the\nhandshake state from TLSBasicSupport, which both SSLNetVConnection and\nQUICNetVConnection implement.\n\nFixes: #13730"
    },
    {
      "commit": "4de94cd962d67291c72d2c402b07c7e9cfd4a092",
      "tree": "4416e8f3587f50b1e89a4c89435b1841a2f557f7",
      "parents": [
        "9ddb75d4598bd4ed06aa22fb744d78ae6a047808"
      ],
      "author": {
        "name": "JosiahWI",
        "email": "41302989+JosiahWI@users.noreply.github.com",
        "time": "Mon Oct 12 17:17:51 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 17:17:51 2026 -0500"
      },
      "message": "Protect OCSP `query_responder` event cancellation (#13829)\n\nThe `query_responder` routine in OCSPStapling schedues an event for\nan HTTP request. If the request does not complete within a timeout,\nit checks that the event has not started yet, and cancels it if so.\nThere is a TOCTOU race between the check and the event cancellation,\nsuch that the event can be initiated and completed after the check,\nand the cancellation can be a use-after-free. This bug is highly\nunlikely to be observed in practice, but this patch eliminates the\nrisk by taking the lock before the check and holding it through\nthe cancellation."
    },
    {
      "commit": "9ddb75d4598bd4ed06aa22fb744d78ae6a047808",
      "tree": "0ffab4d268d382d63b4944899f0826cdca6f61f5",
      "parents": [
        "d9027d96dd2004bdc0d080db3d07489a6ba4859a"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Mon Oct 12 16:55:04 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 16:55:04 2026 -0500"
      },
      "message": "benchmark_HdrParse: Report unreadable corpus directories (#13792)\n\n--corpus-dir loaded nothing and gave no warning when the directory was\nmissing or unreadable, and an entry whose type could not be read ended\nthe tool with an uncaught filesystem_error.  Iterate with the\nerror_code overloads and warn the same way as for an unreadable\n--corpus-file.\n\nAlso correct the comment that says which cases must fully parse, and\nqualify isspace/isprint with std:: in test_URL.cc."
    },
    {
      "commit": "d9027d96dd2004bdc0d080db3d07489a6ba4859a",
      "tree": "4ffa7d6bf322ad9886cbe6b2768c26b2c3f9a877",
      "parents": [
        "ed755d8b7e5ab491aa5ca57aae9d0e07c2ed393c"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Mon Oct 12 16:07:50 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 16:07:50 2026 -0500"
      },
      "message": "Pin selection time in NextHop failover tests (#13802)\n\nConsistent-hash and round-robin failover tests assume down parents\nstay unavailable while they walk the rings. Their one-second retry\ninterval can expire on slow CI workers, allowing a previously failed\nparent to be selected where the tests expect a different parent.\n\nThis change keeps selection time fixed during the failover checks by\npassing a captured timestamp through the existing findNextHop argument.\nThe retry checks explicitly use a future timestamp so the tests still\ncover down parents becoming retryable.\n\nCo-authored-by: GPT-6.1 Sol High\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "ed755d8b7e5ab491aa5ca57aae9d0e07c2ed393c",
      "tree": "90b2bd0e8ba9ba1bd9319802e23329c677de806f",
      "parents": [
        "361a56eeac7ecd48b5c4e3d4abde8c050626e4af"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Mon Oct 12 15:53:07 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 15:53:07 2026 -0500"
      },
      "message": "Fix memory leaks after config reloads (#13747)\n\nConfigReloadProgress returned EVENT_DONE without deleting itself, so\nevery reload leaked the checker, its mutex, and a shared_ptr to the\nreload\u0027s main task.  The checker now deletes itself when it stops.\n\nThat alone does not free the task tree.  Each subtask held its parent\nthrough a shared_ptr, and the parent holds its subtasks the same way,\nso a main task with subtasks stayed alive after the coordinator\ndropped it from its reload history.  _parent is now a weak_ptr.\n\nFixes: #13662"
    },
    {
      "commit": "361a56eeac7ecd48b5c4e3d4abde8c050626e4af",
      "tree": "ab64bfc46ff8a844c66c2763e8e0aedd7fc7838b",
      "parents": [
        "e17299cacd7dd79f25ab0052ce99a01138ba7857"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Mon Oct 12 15:53:02 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 15:53:02 2026 -0500"
      },
      "message": "stats_over_http: Fix a stack overflow and intercept leaks (#13753)\n\n1. The gzip, deflate and br paths copied the rendered body into a\n   stack array of the body\u0027s size and compressed it into a second\n   stack array.  With the default 1 MiB thread stack, a Prometheus\n   request with 10,000 metrics (a 1.6 MB body) overflowed the event\n   thread\u0027s stack and crashed Traffic Server.  The encoders now stream\n   the body\u0027s IOBuffer blocks into newly allocated IOBuffer blocks.\n\n2. br compressed at quality 11, brotli\u0027s slowest setting, with a 4 MiB\n   window, and ignored the encoder that the plugin creates for it.  It\n   now uses that encoder (quality 6, 64 KiB window).\n\n3. The plugin did not release the intercept continuation or its state\n   when a request ended early.  The state is the zlib stream or brotli\n   encoder, the request and response buffers, and the vconn.  A\n   request ends early when the transaction ends before it connects to\n   the intercept (NET_ACCEPT_FAILED) or before the plugin reads the\n   request (EOS), or when the client closes the connection during the\n   response (write ERROR).  Each such request leaked what it had\n   allocated: about 1.5 MB for an uncompressed Prometheus response with\n   10,000 metrics."
    },
    {
      "commit": "e17299cacd7dd79f25ab0052ce99a01138ba7857",
      "tree": "05d8b645d4c6214b77a23cc85fdfbe01419d70fa",
      "parents": [
        "21246d3ebcafce39167546fc32161e4e201b1bce"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Mon Oct 12 15:52:33 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 15:52:33 2026 -0500"
      },
      "message": "libswoc: Validate CIDR prefix bounds (#13756)\n\nIPMask stores its width in one byte and did not check the parsed\nvalue, so a prefix such as /256 wrapped to /0 and matched every address\nin the family.  The range and network parsers also accepted a prefix\nwider than the address, such as 10.0.0.1/33 or ::1/129.  A mistyped\nprefix in a configuration that takes address ranges was therefore\naccepted as a different network instead of being rejected.\n\nThis rejects a prefix that is wider than the address family."
    },
    {
      "commit": "21246d3ebcafce39167546fc32161e4e201b1bce",
      "tree": "3b066037255fde713715dfffac9654e0cf2de459",
      "parents": [
        "d7964f38559d9a14ae85c8e7025677549a5a2081"
      ],
      "author": {
        "name": "Leif Hedstrom",
        "email": "zwoop@apache.org",
        "time": "Mon Oct 12 14:31:18 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 14:31:18 2026 -0600"
      },
      "message": "HRW: Adds a NORM normalization modifier for strings (#13587)\n\n* header_rewrite: add [NORM] modifier to normalize values\n\nA client can evade a string or regex condition by escaping any\ncharacter of the pattern, so [NORM] normalizes the condition\u0027s value\nbefore it is matched. Normalization is percent-decoding for now, but\nthe name leaves room for more. Applying it in a non-virtual\nappend_value() wrapper means it also covers regexes and %{} expansions\ninside operator values, neither of which the matcher-level modifiers\n(PRE/SUF/MID/EXT) reach.\n\nTeaching the tokenizer that %{} spans whitespace is what lets the\nmods be written inside the braces, as in %{CLIENT-URL:PATH [NORM]}.\n\n* hrw4u: support the header_rewrite [NORM] modifier\n\nConditions spell it with the existing \"with\" clause. Interpolated\nvalues reuse the same word rather than inventing a second syntax for\nthe same concept, so \"{inbound.url.path with NORM}\" compiles to\n%{CLIENT-URL:PATH [NORM]}, and both forms round-trip through u4wrh.\n\nNORM is the only modifier accepted on a value, since the others just\nchange how a condition compares and would silently do nothing there.\n\n* Address Copilot review comments\n\nDecode with a local loop instead of TSStringPercentDecode, so escaped\ncontrol characters stay encoded and a [NORM] expansion cannot inject\na header field, and incomplete escapes survive. Also keep a [] that\nbelongs to a qualifier, keep [MODS] on %{} blocks u4wrh cannot map,\nand collapse repeated value modifiers, which header_rewrite rejects."
    },
    {
      "commit": "d7964f38559d9a14ae85c8e7025677549a5a2081",
      "tree": "8a01ec56bcd36c1b6b3b415a3387fcd974325eb3",
      "parents": [
        "09f27b8458c27cad2d9fb733594fbb0ab8bd5001"
      ],
      "author": {
        "name": "Arthur Chan",
        "email": "arthur.chan@adalogics.com",
        "time": "Mon Oct 12 01:52:16 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 17:52:16 2026 -0700"
      },
      "message": "OSS-Fuzz: Add new fuzzer targets chunk processing (#13738)\n\n* OSS-Fuzz: Add new fuzzer targets chunk processing\n\nSigned-off-by: Arthur Chan \u003carthur.chan@adalogics.com\u003e\n\n* Update corpora\n\nSigned-off-by: Arthur SC Chan \u003carthur.chan@adalogics.com\u003e\n\n* Prepare corpora zip file\n\nSigned-off-by: Arthur Chan \u003carthur.chan@adalogics.com\u003e\n\n* Fix linting\n\nSigned-off-by: Arthur Chan \u003carthur.chan@adalogics.com\u003e\n\n---------\n\nSigned-off-by: Arthur Chan \u003carthur.chan@adalogics.com\u003e\nSigned-off-by: Arthur SC Chan \u003carthur.chan@adalogics.com\u003e"
    },
    {
      "commit": "09f27b8458c27cad2d9fb733594fbb0ab8bd5001",
      "tree": "466cb5da4b6a28245f9eb22e19ccf1d50492a844",
      "parents": [
        "a67927e9905d7c5544055ed3b56b11212f13d8e9"
      ],
      "author": {
        "name": "Brian Olsen",
        "email": "brian_olsen2@comcast.com",
        "time": "Sat Oct 10 15:27:57 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 15:27:57 2026 -0600"
      },
      "message": "Add proxy.config.http.bypass_parent (#13801)\n\n* Add proxy.config.http.bypass_parent\n\nAllow a transaction to skip parent.config, next-hop strategy, and\nplugin-chosen parent selection and connect straight to the remapped\norigin, e.g. per remap rule via conf_remap. It yields to\nno_dns_just_forward_to_parent, which leaves origin DNS to the parent.\n\n* Reset parent_result when bypass_parent goes direct\n\nFields left over from an earlier parent selection (retry,\ndo_not_cache_response, use_pristine, a plugin-set record) are read\nwithout checking result and could leak into the direct connection.\nAlso keep all CONNECT test processes in StillRunningAfter, since\nrepeated assignment replaced the earlier ones.\n\n* Compare override header before releasing its MLocs\n\nReturning a string_view into the header after releasing the field and\nheader handles relied on undocumented lifetime behavior. Parse the\nheader into an enum while the handles are still held."
    },
    {
      "commit": "a67927e9905d7c5544055ed3b56b11212f13d8e9",
      "tree": "1b2c754f371ef793a13c227976a9d21c59d8a774",
      "parents": [
        "f35dfae25464e55e2a57bf86e8b7831355a49141"
      ],
      "author": {
        "name": "JosiahWI",
        "email": "41302989+JosiahWI@users.noreply.github.com",
        "time": "Sat Oct 10 14:36:12 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 14:36:12 2026 -0500"
      },
      "message": "Pass nullptr to net `mainEvent` callback (#13824)\n\nSince 974e8e3 (in 2015), it is no longer necessary for `mainEvent` to\ninspect its `Event`, so callers no longer need to build a dummy `Event`."
    },
    {
      "commit": "f35dfae25464e55e2a57bf86e8b7831355a49141",
      "tree": "d17ca4c2123e30c8ee100906524bee6c393bdd1a",
      "parents": [
        "b8397f19c19390fa3304769bf2fa045b6b58234e"
      ],
      "author": {
        "name": "JosiahWI",
        "email": "41302989+JosiahWI@users.noreply.github.com",
        "time": "Sat Oct 10 13:35:20 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 13:35:20 2026 -0500"
      },
      "message": "Document Continuation.h (#13804)\n\n* Document Continuation.h\n\nThis patch adds Doxygen comments to Continuation.h. The comments are worded\nand formatted according to a Claude skill which has not been publicized.\n\n* Make changes suggested by Brian Neradt\n\n * Fix `thread_affinity` docs\n * Don\u0027t mention `reinterpret_cast` UB\n * Mention first-base requirement\n * Fix formatting inconsistencies\n * Explain reason for null guard in setting affinity"
    },
    {
      "commit": "b8397f19c19390fa3304769bf2fa045b6b58234e",
      "tree": "7fdf596e0407f7395d658200dd6b1fc35e37659e",
      "parents": [
        "95c5217fc960620ef24fc0d2bee4436f68cce15e"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Sat Oct 10 11:58:32 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 11:58:32 2026 -0500"
      },
      "message": "abuse_shield: address pruning cpu load (#13819)\n\nThe abuse_shield maintenance task pruned rule buckets for every tracked\nIP once per second. Each pass snapshots all three trackers under their\ntable locks, then locks every entry to erase buckets for rules that are\nno longer configured. With 100k slots per tracker this cost about 0.9%\nof ATS CPU on production hosts, and between reloads it never found\nanything to remove.\n\nObsolete buckets only appear after a configuration reload, either left\nbehind by the reload or recreated by a hook still holding the\npre-reload configuration for the rest of its callback. This patch\naddresses this by pruning on reload and then for only the next five\nmaintenance passes, which covers that window with a wide margin.\nTracker stats continue to sync every second.\n\nPruning now reports how many buckets it removed, and the final\npost-reload pass logs a warning if it still removes any. Debt\nreplenishment already keeps such a bucket from pinning its tracker\nslot, but finding one would mean a hook held the old configuration\nlonger than this window assumes.\n\nCo-authored-by: Claude Opus 5.5 Medium \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "95c5217fc960620ef24fc0d2bee4436f68cce15e",
      "tree": "eb057d8158f8f22cc753ed641df3443b0a86fc78",
      "parents": [
        "490a274fcf34a1720ccfabdf40f678d2e1c9343e"
      ],
      "author": {
        "name": "Mohak Narang",
        "email": "narangmohak9@gmail.com",
        "time": "Fri Oct 09 05:31:38 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 13:31:38 2026 +0900"
      },
      "message": "hrw4u: map early request headers as inbound (#13813)\n\n* hrw4u: map early request headers as inbound\n\nMake u4wrh emit client request header targets at PRE_REMAP and READ_REQUEST so its output remains valid input to hrw4u.\n\nFixes: #13619\n\n* test: add newlines to hrw4u fixtures"
    },
    {
      "commit": "490a274fcf34a1720ccfabdf40f678d2e1c9343e",
      "tree": "5168ba52e025fae156fc39ec381f618df1bea8ce",
      "parents": [
        "67e30858cdf393c36d537818384ee11b4faa678d"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Fri Oct 09 07:42:43 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 07:42:43 2026 +0900"
      },
      "message": "hrw4u: require Python 3.12 (#13815)\n\nThree modules already use f-string syntax that only 3.12 accepts\n(PEP 701), so the declared \u003e\u003d3.11 has never been importable on 3.11.\n3.12 is old enough to require, which is simpler than rewriting the\ncode for a version nothing tests against."
    },
    {
      "commit": "67e30858cdf393c36d537818384ee11b4faa678d",
      "tree": "e575f183db4384bd033ef8110001f43cc5cdebba",
      "parents": [
        "c577715bec245de561c00c5a808c3e83bf3635a5"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Fri Oct 09 07:42:26 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 07:42:26 2026 +0900"
      },
      "message": "hrw4u: remove the bare operator statement that never compiled (#13705)\n\n* hrw4u: remove the bare operator statement that never compiled\n\nThe grammar\u0027s `op\u003dIDENT SEMICOLON` alternative parsed, but the compiler\nrejected everything it matched: the emit path was gated on a statement\nfunction having no argument validator, and every entry in\nSTATEMENT_FUNCTION_MAP declares one -- `no-op` included, via\narg_count(0). Known operators got a \"requires an argument\" error that\nis wrong for the zero-arity ones; any other identifier got \"Unknown\noperator or invalid standalone use\". The call form is the only spelling\nthe docs, the u4wrh reverse conversion, and the test corpus produce.\n\n* hrw4u: expect BoolValue for skip-remap(true) after rebase\n\n#13699 made ASTVisitor._extract_value return BoolValue for true/false,\nso the renamed test_bool_arg must match it like the other bool\nassertions in this file."
    },
    {
      "commit": "c577715bec245de561c00c5a808c3e83bf3635a5",
      "tree": "95b5600beabd7a5b04b7d81cdbdeeb925ef1f382",
      "parents": [
        "7d3ec104ab86dac835be94deebb379bb54390d3b"
      ],
      "author": {
        "name": "JosiahWI",
        "email": "41302989+JosiahWI@users.noreply.github.com",
        "time": "Thu Oct 08 15:11:49 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 15:11:49 2026 -0500"
      },
      "message": "Document Action.h (#13812)\n\n* Document Action.h\n\nThis patch adds Doxygen comments to Action.h. The comments are worded and\nformatted according to a Claude skill which has not been published."
    },
    {
      "commit": "7d3ec104ab86dac835be94deebb379bb54390d3b",
      "tree": "9eb3d01f5e15de4bdb8facb4f223e65fad5866bb",
      "parents": [
        "431c0f2dc1eac3ce49b69583b308a516903f2730"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Oct 08 12:52:21 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 12:52:21 2026 -0500"
      },
      "message": "abuse_shield: Replenish token debt before eviction (#13816)\n\nTracker entries with token debt are protected from eviction, but debt\nwas read from the stored balance, which only replenishes on the next\nconsume. An IP that went into debt and then stopped sending, or a\nbucket left behind by a removed rule, stayed in debt indefinitely and\npinned one of the ip_tracking.slots. Over time this shrinks effective\ntracker capacity and raises events_untracked and scan_exhausted.\n\nThis patch addresses this by having each token bucket remember the\nrate and burst of its latest consume, so token reads report the\ntime-replenished balance without mutating bucket state. Debt checks,\nrate-exceeded checks, and logged token counts all use this view, so\ngenuinely abusive IPs remain protected while quiet ones become\nevictable once their debt is repaid. This also makes a missed prune of\nobsolete rule buckets harmless.\n\nCo-authored-by: Claude Opus 5.5 Medium"
    },
    {
      "commit": "431c0f2dc1eac3ce49b69583b308a516903f2730",
      "tree": "fada50bd6533d9b40b43961d3ebce431f06f9cc4",
      "parents": [
        "5cc13fbfa00c6d7fc0727a7defa6831c62f59671"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Thu Oct 08 07:44:35 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 07:44:35 2026 +0900"
      },
      "message": "cache: move CLFUS value-metric test to Catch2 (#13785)\n\n* cache: move CLFUS value-metric test to Catch2\n\nThe ram_cache_clfus_value regression test only ran under traffic_server\n-R; as a Catch2 case it runs with ctest. The value helper becomes a\nstatic constexpr member so the unit test can reach it.\n\n* cache: keep CLFUS value helper private to tests\n\nReach the value metric through the existing RamCacheCLFUSTestAccess\nfriend instead of widening RamCacheCLFUS\u0027s public surface for a test,\nand restore the static_assert messages that STATIC_REQUIRE replaced\nwith the stringized expression."
    },
    {
      "commit": "5cc13fbfa00c6d7fc0727a7defa6831c62f59671",
      "tree": "3c109ba6c65147d7d7830f38794b82cc72727ba8",
      "parents": [
        "490727dd09e1ecf6aacaa4161ed9099c7225f61c"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Thu Oct 08 07:44:14 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 07:44:14 2026 +0900"
      },
      "message": "cache: reject a Doc longer than the bytes read (#13768)\n\n* cache: reject a Doc longer than the bytes read\n\nhandleReadDone trusts doc-\u003elen and doc-\u003ehlen, and with STORE_COLLISION\nit does so before the caller checks the key. A Dir entry whose size is\nsmaller than the Doc at its offset, such as one inserted after the shm\ndirectory snapshot at shutdown, lets unmarshal walk past the read\nbuffer and corrupt the IOBuffer freelist.\n\n* cache: test a Doc shorter than its header\n\nA len below sizeof(Doc) wraps the hlen bound, so the first clause is\nthe only thing that rejects it.\n\n* cache: treat a foreign Doc that does not fit as a collision\n\nMarking any Doc that does not fit the read as corrupt also caught docs\nbehind a colliding dir entry. The Middle read path fails on a corrupt\ndoc instead of probing on, so the response in flight was truncated even\nthough our fragment could still be further down the chain.\n\n* cache: keep a corrupt Doc out of the overwrite first_buf\n\nopenWriteOverwrite never checked DOC_CORRUPT, so a Doc rejected by\nhandleReadDone still landed in first_buf, where get_header and\nget_single_data trust its len and hlen. The overwrite still replaces\nthe bad dir entry in place."
    },
    {
      "commit": "490727dd09e1ecf6aacaa4161ed9099c7225f61c",
      "tree": "7cf22c39acd0cb4e8e3f08682fafc4f861ff5546",
      "parents": [
        "71a60004cf5cc49b527367421ec789573e8f4f76"
      ],
      "author": {
        "name": "Phong Nguyen",
        "email": "phongn@gmail.com",
        "time": "Wed Oct 07 10:41:24 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 10:41:24 2026 -0700"
      },
      "message": "esi: link tsutil via esitest for all ESI tests (#13797)\n\nesicore omits tsutil so plugins don\u0027t embed a second copy, and each\nESI test had to link ts::tsutil itself. test_gzip, test_utils and\ntest_combo_handler_utils didn\u0027t, and fail to link under mold, which\nextracts esicore members that GNU ld and lld leave out. Link tsutil\nonce from the test-only esitest library instead.\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "71a60004cf5cc49b527367421ec789573e8f4f76",
      "tree": "3f7c71f726e65345172c574161f039605102f44b",
      "parents": [
        "01f8a7e46aabcd576eb34b42d78746e7b22da4fa"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Wed Oct 07 07:35:11 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 07:35:11 2026 +0900"
      },
      "message": "cache: drop CacheTest.cc and RegressionSM from traffic_server (#13786)\n\nThe level-gated cache tests now run under ctest. The remaining cache\nop-sequence test is removed rather than ported: its data checks never\ntook effect, and its paths are covered elsewhere. SDK_API_TSCache\ncovers the non-HTTP cache API, and the range autest covers do_io_pread\non cached range hits. The non-HTTP lookup it also exercised has no\ncallers."
    },
    {
      "commit": "01f8a7e46aabcd576eb34b42d78746e7b22da4fa",
      "tree": "c1f50eb3bcb632a6abaf4e82d43ba8bf635f0f54",
      "parents": [
        "e4c02a17b5c3257c0e370487ef259cc70c282a9b"
      ],
      "author": {
        "name": "JosiahWI",
        "email": "41302989+JosiahWI@users.noreply.github.com",
        "time": "Tue Oct 06 12:33:49 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 12:33:49 2026 -0500"
      },
      "message": "Add doxygen comments to DiagsTypes.hh (#13262)\n\nThis is a documentation patch generated with Claude."
    },
    {
      "commit": "e4c02a17b5c3257c0e370487ef259cc70c282a9b",
      "tree": "9bc6c5f67464700d6424cd20c66c641c2debbc2c",
      "parents": [
        "ebc6d8a2821ff63c1f8978f8a156d5a691e87385"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Tue Oct 06 08:16:28 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 08:16:28 2026 -0700"
      },
      "message": "Remove unnecessary copies flagged by static analysis (#13591)\n\nAdd std::move where a local\u0027s last use was a copy into a container or a\nby-value parameter, as flagged by static analysis; no moved-from object is\nread again. The copy in cachekey\u0027s Pattern::process stays, because a move\nthere would also write past an empty capture vector, and that bug gets its\nown change."
    },
    {
      "commit": "ebc6d8a2821ff63c1f8978f8a156d5a691e87385",
      "tree": "3dc1b78e91077e4e74f4cb2cd1aaa51d415794a6",
      "parents": [
        "2d0992006017ff048e206b7d84d20cb5de1778e6"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Tue Oct 06 08:16:23 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 08:16:23 2026 -0700"
      },
      "message": "logging: unit-test time-based log rolling across a synthetic midnight (#13758)\n\nThe AuTest harness turns log rolling off, so no suite run exercised\nautomatic rolling. test_LogRolling drives LogObject::roll_files() across a\nsynthetic midnight: a daily log rolls just after 00:00 into a *.old file\nnamed for the interval, once per boundary, never with rolling_enabled 0,\nand later records land in the reopened file. It runs in UTC on fixed 2030\ndates so no DST change can move a midnight."
    },
    {
      "commit": "2d0992006017ff048e206b7d84d20cb5de1778e6",
      "tree": "dcf228e5c03763eeb2390eebfb9ee5e840bdee70",
      "parents": [
        "285d26a11f6969af408a49f6cab85c361957f3d3"
      ],
      "author": {
        "name": "Damian Meden",
        "email": "dmeden@apache.org",
        "time": "Tue Oct 06 17:03:22 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 17:03:22 2026 +0200"
      },
      "message": "Traffic ctl plugin list format (#13626)\n\n* traffic_ctl: honor -f json for plugin list\n\nplugin_list() formatted its table straight to std::cout and only\nconsulted the printer on the error path, so --format was silently\nignored on success and the output could not be consumed as JSON.\n\nMove the table into a PluginListPrinter so the command follows the\nsame path as every other one: the base class dispatches on format,\nemitting the JSON-RPC envelope for -f json and delegating to the\nprinter for text. Text output is unchanged.\n\n* Add autests for traffic_ctl plugin list output\n\nAssert the payload through -f json rather than the text table. Column\nwidths are a presentation detail, so pinning them down byte for byte\nonly makes the test brittle against cosmetic changes. Text mode gets a\nsmoke check that it still renders a table.\n\nThe parse is the point. A gold file would have matched unparseable\noutput indefinitely; the command itself had no autest before this.\n\nThe empty plugin.config case gets its own test because a populated\nconfig never reaches it, and because TrafficCtl hardcodes its ATS\nprocess name, so two instances cannot share one file.\n\nAdds the plugin_config parameter the DSL was missing. The payload is\nasserted with validate_json_contains, naming the result node so the\ncheck also fails if it ever carries a sibling of data."
    },
    {
      "commit": "285d26a11f6969af408a49f6cab85c361957f3d3",
      "tree": "a9926babfba6559d36a01f188d1836b67c313b99",
      "parents": [
        "967432bebeab3c0b211a8d7c247ed7aea6b59ee6"
      ],
      "author": {
        "name": "Damian Meden",
        "email": "dmeden@apache.org",
        "time": "Tue Oct 06 17:02:01 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 17:02:01 2026 +0200"
      },
      "message": "hostdb: keep records in filtered status output (#13732)\n\nget_hostdb_status created a partition\u0027s \"records\" key only as a side\neffect of push_back inside the record loop. With a HOSTNAME filter, a\npartition that held entries but no match was still listed, with its id\nand no records key, so `traffic_ctl hostdb status \u003cname\u003e` returned bare\n{\"id\": N} stubs next to the real matches.\n\nConstruct \"records\" as an empty sequence before the loop, as #13609 did\nfor \"partitions\", so every listed partition carries the array. Add an\nautest that populates HostDB through DNS, with the default 64 partitions\nand with a single one, and checks each filtered answer against the\nunfiltered one.\n\nFixes: #13710"
    },
    {
      "commit": "967432bebeab3c0b211a8d7c247ed7aea6b59ee6",
      "tree": "2e7f16778021cc2ce3ac3d6aa88511c5a5418606",
      "parents": [
        "a655c6ac55f2307cf984bc4cab6f287407172525"
      ],
      "author": {
        "name": "Kit Chan",
        "email": "kichan@apache.org",
        "time": "Tue Oct 06 07:27:10 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 07:27:10 2026 -0700"
      },
      "message": "Update CIFuzz actions to specific versions (#13796)"
    },
    {
      "commit": "a655c6ac55f2307cf984bc4cab6f287407172525",
      "tree": "0dc48e4cabe23fd9bd0be2cfae056e0913db5d64",
      "parents": [
        "a830bf595eaa2b8308edd148274344a1b9fb47e7"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Tue Oct 06 06:58:27 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 06:58:27 2026 +0900"
      },
      "message": "hrw4u: report each sandbox warning at the use that triggers it (#13739)\n\nA resolver buffered its policy warning before validating the construct,\nand the visitor drained it only on success, so a failed construct\u0027s\nwarning surfaced against the next one that resolved. The visitor also\nmemoized condition resolution, which warned only at a condition\u0027s first\nuse and hid the denial message of a bare denied condition. Variables in\nconditions and assignments skipped the `variables` check that the docs\npromise for all variable usage."
    },
    {
      "commit": "a830bf595eaa2b8308edd148274344a1b9fb47e7",
      "tree": "a595a262397f3fc51643790753bf2b5e45a099e8",
      "parents": [
        "1d7ff6ed868381721e94b3fde588b0d741b2bf36"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Tue Oct 06 06:57:42 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 06:57:42 2026 +0900"
      },
      "message": "hrw4u: give AST nodes a file, line and column span (#13665)\n\nA line number alone cannot say where a node came from: procedure\ninlining splices nodes in from a second file. Replace Node.line with a\nSpan naming the file too, and give ASTVisitor the filename to build it\nfrom. Node.line goes outright rather than surviving as a property over\nspan -- keeping it would let new code go on producing locations that\ncannot name their own file. The eight \"Unhandled ... at line N\" raises\nhad the same gap and now share one _unhandled() helper.\n\nTwo shapes change with it. Target.from_dotted guessed a namespace/field\nsplit no caller wanted; every table lookup matches the whole dotted\nname, so Assignment carries it verbatim. VarSection.declarations\nbecomes items, since comments sit in it alongside the declarations.\n\ntest_ast_nodes asserted AttributeError on writing an unknown Span\nfield, which proved nothing: FrozenInstanceError subclasses it, so\nfrozen intercepted the write and slots was never exercised. It checks\nthe layout instead."
    },
    {
      "commit": "1d7ff6ed868381721e94b3fde588b0d741b2bf36",
      "tree": "b2836d3ac2e729f5419aa4e793fcf161f67dae3b",
      "parents": [
        "ff6ddf83e5ac8fe2e4cbaf70a69d5ae87a7c1663"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Mon Oct 05 16:13:02 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 16:13:02 2026 -0500"
      },
      "message": "Fix BoringSSL dual-certificate default selection (#13712)\n\nWith BoringSSL, a default entry containing RSA and EC certificates serves only the last certificate to clients with no SNI or an unknown SNI. Clients restricted to the other key type fail with `handshake_failure`, despite a compatible certificate being configured.\n\nAfter name and address lookups miss, select the existing `*` entry for the client’s key type. This reuses the entries maintained by certificate loading and secret updates; OpenSSL’s native dual-certificate selection is unchanged. A default `action: tunnel` entry on a transparent port also applies to these fallback clients.\n\nAdd regression coverage for both certificate orders, RSA and ECDSA clients, TLS 1.2 and TLS 1.3, and absent, unknown, and matching SNI. The original callback fails the regression with alert 40; the fix passes it with BoringSSL and preserves OpenSSL behavior."
    },
    {
      "commit": "ff6ddf83e5ac8fe2e4cbaf70a69d5ae87a7c1663",
      "tree": "f61e75e84b38a527d051fb6c0b268f4401a6de2c",
      "parents": [
        "617b749bb83279a9c6b5042066291a84a3364eea"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Mon Oct 05 14:42:33 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 14:42:33 2026 -0500"
      },
      "message": "Reduce repeated work in HTTP header parsing (#13376)\n\nReduce repeated work in HTTP header parsing.\n\n1. Replace per-byte libc calls in URL compliance validation with a vectorizable, locale-independent ASCII range check.\n2. Simplify request-target validation using the stored URL fields.\n3. Combine field-name colon scanning, hashing, and character validation into one pass, reusing the existing well-known-string table.\n4. Skip duplicate lookup for well-known fields when their presence bit is clear.\n5. Append adjacent duplicate fields in constant time instead of searching the duplicate chain.\n\nIncludes a header parsing benchmark harness and regression tests for validation, field-name scanning, duplicate attachment, and parser reuse."
    },
    {
      "commit": "617b749bb83279a9c6b5042066291a84a3364eea",
      "tree": "be9ce785defaebf5193f65df42777bbd12088d1e",
      "parents": [
        "2b65f92e32a5d0d52eb8c64fba76fe5b522969b2"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Mon Oct 05 13:04:13 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 13:04:13 2026 -0500"
      },
      "message": "Reduce noisy HTTP/2 origin logs (#13788)\n\nExpected HTTP/2 flow-control pauses and rejected origin connection reuse\ncandidates flood diags.log with warnings. This noise obscures actionable\nfailures and makes normal behavior look like failed transactions.\n\nThis change moves expected pauses and ENFORCED reuse rejections to their\nexisting debug channels. It keeps PERMISSIVE reuse mismatches visible as\nthrottled warnings so operators can audit certificate failures, and uses\nAction\u003dRejectReuse to distinguish rejecting a candidate from terminating\na connection.\n\nCo-authored-by: Codex GPT-6.1 Sol High"
    },
    {
      "commit": "2b65f92e32a5d0d52eb8c64fba76fe5b522969b2",
      "tree": "3d64330f7924f3f987e060b4a5e173b7ddcd38f3",
      "parents": [
        "04008efa02abc471caf3eef3b4b445c3b6a217af"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Mon Oct 05 07:52:39 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 07:52:39 2026 +0900"
      },
      "message": "cache: keep the stripe locked after the shutdown dir sync (#13767)\n\nd039375185 made StripeSM::shutdown() release the stripe lock to avoid\na deadlock on a second shutdown pass. That let writers admitted after\nthe snapshot insert Dir entries for data that only reached the\naggregation buffer. The shm directory carries those entries into the\nnext start, where they point at whatever the new process writes there.\n\nHold the lock until exit again. Writers, readers and any AIO\ncompletion for an already-synced stripe wait on the lock until exit.\nOverlapping shutdown passes can deadlock on stripes of different\ndisks, but neither marks the directory clean; a separate change runs\nthe shutdown only once."
    },
    {
      "commit": "04008efa02abc471caf3eef3b4b445c3b6a217af",
      "tree": "790b58e67715db813cc17c4db02a27462d35420f",
      "parents": [
        "3266bd08fd7b1520cf635b7580b30369d78fda46"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Mon Oct 05 07:51:38 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 07:51:38 2026 +0900"
      },
      "message": "hrw4u: enforce sandbox policy on value functions (#13674)\n\n* hrw4u: enforce sandbox policy on value functions\n\nThe sandbox `functions` deny/warn list was only consulted for statement\nfunctions, so an entry naming a function used as a value in an\nexpression was accepted by the loader and then silently ignored.\n`access()`, which reaches the filesystem, was among them.\n\nThe split between the two resolvers is an implementation detail; the\ngrammar has one `functionCall` rule and the policy YAML exposes one\n`functions` category, so both now go through the same check.\n\n* doc: list set-body and set-body-from-file with the other functions\n\nBoth are statement functions in their own right — `set-body(\"x\")` and\n`set-body-from-file(\"/p\")` compile — and the schema enum already accepts\nthem, but neither the sandbox function table nor the operator mapping\ntable listed them all. Both tables now match STATEMENT_FUNCTION_MAP.\n\n* hrw4u: enforce the sandbox policy inside string interpolation\n\n`_substitute_strings` handled a `SandboxDenialError` like any symbol\nerror, so a function or condition reached only through `\"{...}\"` was\nreported without its policy message. It is now reported as a denial,\nand the rest of the string is still checked so every denial in it is\nlisted."
    },
    {
      "commit": "3266bd08fd7b1520cf635b7580b30369d78fda46",
      "tree": "86ac93ce311a2ad079e5bae9a99531ddc5ef2949",
      "parents": [
        "152ed11d7051c5c09ff347e735804e2f3e1c3c92"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Fri Oct 02 23:09:40 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 23:09:40 2026 -0500"
      },
      "message": "Frame empty TLS origin responses in AuTests (#13763)\n\nPreparing ATS CI to move from fedora:44 to fedora:45 exposed TLS AuTest\nfailures with OpenSSL 4. Empty origin responses without a body length\nrely on TLS shutdown for completion. Closing without close_notify now\nsurfaces as a TLS read error, which can leave clients waiting.\n\nThis patch frames empty TLS origin responses and explicitly registered\nfallback 404 responses with Content-Length: 0. Separate plaintext remap\nfixtures retain coverage of ATS\u0027s chunked conversion. The core TLS read\nerror handling defect is tracked separately in #13784.\n\nCo-authored-by: GPT-6.1 Sol High"
    },
    {
      "commit": "152ed11d7051c5c09ff347e735804e2f3e1c3c92",
      "tree": "b6ba12bf82970b6f2d11e03790053e3c1767e5dd",
      "parents": [
        "1a7dbe8e4eceea5c2bc27cb3fa04aa9716bbfbed"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Fri Oct 02 17:46:03 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 17:46:03 2026 -0500"
      },
      "message": "Add live HostDB cache clearing (#13409)\n\nOperators cannot discard stale HostDB entries without restarting Traffic\nServer. A restart interrupts service and delays recovery from incorrect\nDNS data, while a live clear must not invalidate resolutions held by\nactive transactions.\n\nThis patch adds a traffic_ctl command and restricted JSON-RPC method to\nclear cached DNS records under internally enforced partition locks.\nThread-safety annotations cover guarded cache state, and retained record\nhandles let in-flight transactions finish safely.\n\nThis also makes status snapshots scoped, fixing their leaked cache\nrecord references, guards HostDB RPCs during startup, logs clears, and\nverifies empty metrics, in-flight transactions, argument validation,\nand repopulation without a restart.\n\nFixes: #9022\n\nCo-authored-by: Codex GPT-6 Astra Medium"
    },
    {
      "commit": "1a7dbe8e4eceea5c2bc27cb3fa04aa9716bbfbed",
      "tree": "948305325575d4acdad1cbabedd0760b7c79308d",
      "parents": [
        "00a22f20810ce5fd6ac4ca297861e5d39db11aee"
      ],
      "author": {
        "name": "Masakazu Kitajo",
        "email": "maskit@apache.org",
        "time": "Fri Oct 02 14:59:18 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 14:59:18 2026 -0600"
      },
      "message": "Honor TLS handshake hook pauses on BoringSSL (#13729)\n\nOn BoringSSL builds, a plugin that parks the handshake in the client\nhello or cert hook is not waited for. The select certificate callback\ndropped the retry from the client hello step and mapped a cert hook\npause to success, so the handshake carried on without the plugin.\n\nReturn a retry for both. BoringSSL then calls the callback again from\nthe top, so after a cert hook pause the client hello and servername\nsteps are skipped rather than run twice. OpenSSL builds use a separate\ncallback and are unaffected.\n\nThe callback has behaved this way since BoringSSL support for it was\nadded in #8014. The rate_limit_sni_expiry and\ntls_hooks_close_while_parked tests from #13406 rely on the pause and\nfail on BoringSSL builds without this change."
    },
    {
      "commit": "00a22f20810ce5fd6ac4ca297861e5d39db11aee",
      "tree": "e37cb1052702806035019313e659e2e47c37dafd",
      "parents": [
        "289f48e1c8d7310324c5e1c41f4fdfc5b309d03c"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Fri Oct 02 15:56:02 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 13:56:02 2026 -0700"
      },
      "message": "Deliver H2 END_STREAM that arrives while read is throttled (#13780)\n\nWith HTTP/2 to origin, an HTTP/1.1 client receiving a re-chunked\nresponse larger than the buffer water mark could get the whole body\nbut never the terminating chunk. The chunked tunnel disables the\norigin stream\u0027s read VIO when its output backs up. If END_STREAM\narrived during that window, on a DATA frame or on trailers, the stream\ndropped the event that ends the read, and re-enabling the VIO only\nreopened the flow-control window. The transaction then sat until a\ntimeout, logging \"HTTP/2 unknown case\" once a second.\n\nThis patch has the stream remember the final read event it could not\ndeliver because its read VIO was disabled, and schedule that same event\nonce the consumer re-enables the VIO, deferring it again if the\nconsumer has throttled once more by the time it is dispatched. The\nchunked flow-control AuTest gains an HTTP/2 origin case, plus a custom\norigin that ends the stream inside the throttle window on a DATA frame\nand on trailers.\n\nFixes: #13777\n\nCo-authored-by: Claude Opus 5.5 Medium"
    },
    {
      "commit": "289f48e1c8d7310324c5e1c41f4fdfc5b309d03c",
      "tree": "1008bf33a377cc18ed5f45422e9779fb8d9f9125",
      "parents": [
        "1de91c7498fdccda8c8ffbcda9ffd3e826017ea6"
      ],
      "author": {
        "name": "Masakazu Kitajo",
        "email": "maskit@apache.org",
        "time": "Fri Oct 02 14:55:28 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 14:55:28 2026 -0600"
      },
      "message": "tests: drive tls_sni_groups with openssl s_client (#13723)\n\n* tests: drive tls_sni_groups with openssl s_client\n\ncurl reports the key exchange group only when it is linked against\nOpenSSL 3.x, and only spells it \"x25519\" from 3.2 on; a BoringSSL\nbuild prints \"[blank]\" instead, so the x25519 and X25519MLKEM768\nassertions could never pass with BoringSSL. s_client prints the\nnegotiated group itself, on its temp key line or, for TLS 1.3 groups\nwith no legacy key type, its TLS 1.3 group line, so the test can keep\nchecking the group rather than settle for the version and cipher.\n\n* tests: skip tls_sni_groups when openssl is not in PATH"
    },
    {
      "commit": "1de91c7498fdccda8c8ffbcda9ffd3e826017ea6",
      "tree": "12f9bdba78401b6b6bc6227fed0e250eb0d51493",
      "parents": [
        "5e62b2b07f95442fc7dbf7414adcc1a57056437d"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Fri Oct 02 14:10:55 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 14:10:55 2026 -0500"
      },
      "message": "Drain an HTTP/2 origin session after it sends GOAWAY (#13783)\n\nAn HTTP/2 origin that sends a NO_ERROR GOAWAY is promising to finish\nevery stream at or below its last_stream_id, but ATS closed the session\nas soon as the frame arrived. During graceful origin drains, every\nin-flight request on a long-lived, heavily multiplexed session failed\nat once. Non-idempotent requests cannot be retried after they are sent,\nso clients saw bursts of 502 ERR_CONNECT_FAIL responses.\n\nThis patch drains the session instead of closing it. On a NO_ERROR\nGOAWAY from an origin, ATS closes only the streams the origin will not\nprocess, which stay marked retryable, and lets the rest run to\ncompletion. If any remain, the session is half-closed, which removes it\nfrom the pool and stops new streams, and it closes once its last stream\nis released. The existing transaction timeouts bound a drain whose\nstreams never finish. An error GOAWAY, or one that leaves nothing to\nfinish, still closes the session right away, and inbound GOAWAY\nhandling is unchanged.\n\nThe outbound HTTP/2 safe-retry AuTest origin gains modes that answer a\nPOST after a GOAWAY covering it, hold the connection open after a\nGOAWAY that covers nothing, and drain one of three multiplexed streams\nwhile the other two retry.\n\nFixes: #13779\n\nCo-authored-by: Claude Opus 5.5 Medium"
    },
    {
      "commit": "5e62b2b07f95442fc7dbf7414adcc1a57056437d",
      "tree": "7c3c12228648587352d2b32e29eb6f0aee55f337",
      "parents": [
        "a31be25a7c5fdb49b103d4aaa049cf4855c5defc"
      ],
      "author": {
        "name": "Evan Zelkowitz",
        "email": "eze@apache.org",
        "time": "Fri Oct 02 11:41:11 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 11:41:11 2026 -0600"
      },
      "message": "compress: use weak ETags for compressed responses (#13776)\n\n* compress: weaken strong ETags instead of appending -df\n\nEvery compression algorithm shared the same suffixed strong ETag even\nthough their bytes differ, and the suffixed tag never matched at the\norigin on revalidation. A weak ETag is correct for a transformed body\nand lets If-None-Match validate, while If-Range correctly won\u0027t match.\n\nAlso fixing core issue with If-Match: *, which is currently not handled correctly"
    },
    {
      "commit": "a31be25a7c5fdb49b103d4aaa049cf4855c5defc",
      "tree": "9220c93e01443436e39c1673cc1f7403be285d25",
      "parents": [
        "8e3c77e4b8cbd062ddf9ea204d987a6ac1f589ea"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Fri Oct 02 12:11:51 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 12:11:51 2026 -0500"
      },
      "message": "HTTP/2 to origin session pool and reliability fixes (#13447)\n\nLong-lived HTTP/2 origin connections could remain discoverable after\nentering half-close, become unreachable when global pooling was\nconfigured, or be poisoned by a single request\u0027s Connection: close\nheader. Requests assigned to those sessions could fail immediately.\nValid responses could also be rejected when headers used CONTINUATION,\nwhen their payload length followed HEAD or 304 rules, or when normal\nSETTINGS acknowledgments crossed the receive-rate limit. Large-session\nflow control also advertised the connection allowance as each stream\u0027s\nreceive window.\n\nThis makes outbound HTTP/2 session lifecycle consistently thread-local.\nIt always probes the thread pool before configured global pools, ignores\nConnection: close for outbound session shutdown, refuses to re-pool\nhalf-closed sessions, and evicts sessions as soon as they enter local\nhalf-close. HTTP/1.x global pooling behavior remains unchanged.\n\nThis also carries the peer\u0027s not-processed assertion from GOAWAY and\nREFUSED_STREAM into retry selection. Retry admission requires no\nobserved response and either no body or a complete replayable copy,\nincluding during upload failures. Solicited SETTINGS acknowledgments are\nexcluded from the receive limit in both directions because their rate is\nbounded by settings sent by Traffic Server. This patch keeps configured\nstream receive windows separate from the connection allowance.\n\nThis accepts CONTINUATION frames in valid outbound stream states without\ncreating a second transaction and preserves request metadata needed to\nvalidate HEAD and conditional 304 responses. Replay-based AuTests and\ncustom HTTP/2 origins cover session reuse, half-close handling, retries,\nsplit response headers, payload validation, and SETTINGS accounting.\nNegative cases enforce retry and frame-validation boundaries, and\ncounters distinguish admitted retries from unavailable body copies.\n\nCo-authored-by: GPT-6 Astra Medium"
    },
    {
      "commit": "8e3c77e4b8cbd062ddf9ea204d987a6ac1f589ea",
      "tree": "aa538d58ec218794922424b91d0dfca1bb083665",
      "parents": [
        "cabef5b351259a392152e38156ce3fd624a09d7c"
      ],
      "author": {
        "name": "Brian Olsen",
        "email": "brian_olsen2@comcast.com",
        "time": "Fri Oct 02 08:06:21 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 08:06:21 2026 -0600"
      },
      "message": "slice: keep internal write side open; drop body headers (#13751)\n\n* slice: keep internal write side open; drop body headers\n\nWith proxy.config.http.allow_half_open set to 0, half-closing the\nTSHttpConnect write side after sending the request header delivers an\nEOS that ATS treats as a client abort, killing block and prefetch\nrequests. Leave the write side open until the connection is closed,\nand strip every Content-Length/Transfer-Encoding field from the client\nheader since slice never sends a request body on the internal\nconnection. HttpHeader::removeKey now removes all duplicates, as ATS\naccepts repeated Transfer-Encoding: chunked fields.\n\n* slice: walk duplicate chain in removeKey\n\n* slice: close write channel after request header is sent"
    },
    {
      "commit": "cabef5b351259a392152e38156ce3fd624a09d7c",
      "tree": "d1882e81d12931ce67c7328d667bcef666f7ccb1",
      "parents": [
        "972a0f477d8a4af4ea1d74db07be53305d94c3cc"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Thu Oct 01 21:48:53 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 21:48:53 2026 -0700"
      },
      "message": "Fix GCC release-build warnings that break master OS builds (#13770)\n\nGCC 12, 14 and 15 release builds with -Werror stopped on three\noptimization-only warnings that PR CI never builds: an uninitialized\nprotocol_mask in YamlSNIConfig, a -Wfree-nonheap-object false positive\nfrom std::stable_sort in parse_plugin_yaml(), and a -Wrestrict false\npositive in the abuse_shield test. Default the mask to 0, sort with the\nexisting index as tie-breaker, and build the quoted path by appending."
    },
    {
      "commit": "972a0f477d8a4af4ea1d74db07be53305d94c3cc",
      "tree": "09f7fe3852db17e7c92d218f6a0800769e882c36",
      "parents": [
        "959daa1d36a65caa26a39d55975f4c9dd6a5e602"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Thu Oct 01 21:48:42 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 21:48:42 2026 -0700"
      },
      "message": "Fix parsing of bodyless HTTP/2 origin responses over 4 KB (#13782)\n\nA bodyless HTTP/2 origin response reaches HttpSM as 4 KB blocks with EOS,\nand parse_resp() passed eof with every block, so a field cut at a block\nboundary read as truncated input: the client got a 502, or a 302 with the\nrest of its header as the body. Only the last block now carries eof, in\nparse_req() too; tests cover header blocks from 3.8 KB to 900 KB."
    },
    {
      "commit": "959daa1d36a65caa26a39d55975f4c9dd6a5e602",
      "tree": "839905f558a8ef61cc73afc5a69f40006f55f2b6",
      "parents": [
        "527edda8a8876b04506b6729fb3c166d8f0aa56a"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Fri Oct 02 08:00:16 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 08:00:16 2026 +0900"
      },
      "message": "Harden shutdown against repeated exit signals (#13766)\n\nRe-sending SIGTERM/SIGINT is not supported, but one arriving on a\nlater SignalContinuation tick, e.g. during the shutdown_timeout drain,\nscheduled another AutoStopCont that re-ran the whole shutdown path:\nthe cache directory sync on shutdown ran twice, and\nstop_ssl_handshaking() tripped its assert. Make SignalContinuation a\ntwo-state machine so the shutdown path is scheduled exactly once."
    },
    {
      "commit": "527edda8a8876b04506b6729fb3c166d8f0aa56a",
      "tree": "34af3e7a791e88e7de9edccc7493abc8887f983c",
      "parents": [
        "cc1c035196ca98c588ab40e514761c601911b29f"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Oct 01 13:40:26 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 11:40:26 2026 -0700"
      },
      "message": "Remove unused globals rejected by Clang 23 (#13759)\n\nMoving ATS CI from fedora:44 to fedora:45 brings Clang 23. Its\n-Wunused-but-set-global diagnostic flags globals that are assigned but\nnever read. These warnings fail the Fedora CI build because its CMake\npreset treats warnings as errors, blocking the image upgrade.\n\nThis patch removes unused counters and pointer assignments while keeping\nplugin objects registered with the C++ API. It also removes an unused\ncontinuation allocation from the intercept example.\n\nRemoving the unused remap pointer exposes an ownership-tracking\nlimitation in the existing Clang analyzer. This patch explicitly returns\nthe remap plugin through its instance handle so the analyzer can see the\ntransfer to the remap API, which deletes the instance when its rule is\nremoved.\n\nCo-authored-by: Codex GPT-6.1 Sol High"
    },
    {
      "commit": "cc1c035196ca98c588ab40e514761c601911b29f",
      "tree": "380aba0725c39ca164fdbf5b16a7738b9e8b5f74",
      "parents": [
        "7e2560376b7b349c21103aae2574d7b86a1fac2a"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Oct 01 13:31:26 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 13:31:26 2026 -0500"
      },
      "message": "Wait for GOAWAY processing in the abuse shield AuTest (#13764)\n\nThe abuse shield HTTP/2 error test closes its TLS socket immediately\nafter sending GOAWAY. Connection shutdown can race with ATS processing\nthe frame, causing the received GOAWAY counter to miss an event.\n\nThis patch keeps the socket open until ATS closes the connection after\nprocessing GOAWAY. The test continues to require the exact expected\ncounter value.\n\nCo-authored-by: GPT-6.1 Sol High"
    },
    {
      "commit": "7e2560376b7b349c21103aae2574d7b86a1fac2a",
      "tree": "4e4414d8b0510b1c0577f5874b725aa97bacc54f",
      "parents": [
        "dafd12c68c1619d2aad0376d79a37049ec71c0cd"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Oct 01 13:29:33 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 13:29:33 2026 -0500"
      },
      "message": "Fix HTTP flow control policy reload (#13695)\n\nHTTP/2 flow-control changes were reported as reloadable but had no\neffect because connections kept startup-only policy values. The reload\ncallbacks also retained pointers to expired stack variables.\n\nThis patch validates startup and runtime policy values and publishes\nthem through persistent atomic storage for both connection directions.\nEach connection snapshots its policy at initialization so reloads affect\nonly new connections. The regression coverage checks fresh connections\nthrough live updates and records.yaml reloads, and verifies that existing\ninbound connections retain their policy.\n\nFixes: #13694\n\nCo-authored-by: Codex GPT-6 Astra Medium"
    },
    {
      "commit": "dafd12c68c1619d2aad0376d79a37049ec71c0cd",
      "tree": "b1f85e88bb4d354f5838cdeb2c3882d2096cf66e",
      "parents": [
        "fe7cfc94278d05e0eb772f08a14628a0141437e3"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Oct 01 13:11:45 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 13:11:45 2026 -0500"
      },
      "message": "Support OpenSSL 4 certificate accessors in WASM (#13760)\n\nOpenSSL 4 returns const-qualified certificate names and extensions,\nwhich prevents the WASM plugin from building with Fedora 45\u0027s system\nOpenSSL headers.\n\nThis patch accepts read-only certificate names and deduces the extension\npointer type from the accessor, preserving compatibility with older\nOpenSSL versions that return mutable extensions.\n\nCo-authored-by: Codex GPT-6.1 Sol High"
    },
    {
      "commit": "fe7cfc94278d05e0eb772f08a14628a0141437e3",
      "tree": "46fb5f46f21433aff86ce3ff7c1ca1be32354f83",
      "parents": [
        "3952b1864e5b4a80cb08f627bb87bd86bc2214b9"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Oct 01 13:10:35 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 13:10:35 2026 -0500"
      },
      "message": "Handle OpenSSL 4 handshake buffer exhaustion (#13761)\n\nTLS handshakes stall with OpenSSL 4 because an empty memory BIO no\nlonger reports EOF when its empty-read behavior requests a retry. ATS\ntherefore retains the exhausted handshake buffer and never resumes\nreading the client connection.\n\nThis patch checks the pending byte count to detect exhausted handshake\nbuffers and resume socket reads. This check also works with earlier\nOpenSSL releases and removes the unused BoringSSL EOF fallback.\n\nCo-authored-by: Codex GPT-6.1 Sol High"
    },
    {
      "commit": "3952b1864e5b4a80cb08f627bb87bd86bc2214b9",
      "tree": "6563b2d7b735c15bab4f7172ea25eaf3ced73803",
      "parents": [
        "c8935543e28d671ffba1b5245cfc8b069eed4c30"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Oct 01 13:09:29 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 13:09:29 2026 -0500"
      },
      "message": "Python 3.15: accommodate PyYAML without CLoader (#13762)\n\nThe new fedora:45 CI image uses Python 3.15. PyYAML can be installed\nwithout its optional C extension when a matching binary wheel is\nunavailable. The remap ACL AuTests import CLoader unconditionally, so\nthis environment raises ImportError before their test cases can run.\n\nThis patch falls back to PyYAML\u0027s Python loader when CLoader is\nunavailable. Both ACL suites retain the faster C loader when it is\ninstalled, allowing the same tests to run with the updated Fedora image.\n\nCo-authored-by: GPT-6.1 Sol High"
    },
    {
      "commit": "c8935543e28d671ffba1b5245cfc8b069eed4c30",
      "tree": "6ad6437e623b5d927c3143260a3e8950730e20bc",
      "parents": [
        "2fa4963926a7a7deb2987fcbfa3b5c1e2d400872"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Wed Sep 30 14:26:27 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 14:26:27 2026 -0700"
      },
      "message": "lua_global_shutdown: watch both state markers together (#13755)\n\nshutdown_race_client.py waited for the global Lua state\u0027s marker and only\nthen for the remap state\u0027s, but remap_shutdown.lua writes its marker once,\nfor half a second. When the global marker was slow, the remap window\npassed unseen, the client timed out without sending SIGTERM, and the\n\"Traffic Server exited\" run failed. Watch both markers from the start and\ntreat each as satisfied once seen."
    },
    {
      "commit": "2fa4963926a7a7deb2987fcbfa3b5c1e2d400872",
      "tree": "39ecc6c2b0a2182bad468e1b56496666c997041e",
      "parents": [
        "b55a391e3bd8ba143b9f9b0c266f72116c911570"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Wed Sep 30 12:23:09 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 12:23:09 2026 -0700"
      },
      "message": "autest: turn log rolling off by default (#13749)\n\nATS rolls its logs daily at 00:00 UTC by default, so an autest running\nacross midnight had its logs renamed to *.old and its end-of-test content\nchecks read the fresh, empty file; this is what made jax_fingerprint and\nlog-filenames flaky on CI. MakeATSProcess now sets\nproxy.config.log.rolling_enabled to 0 unless called with\ndisable_log_rolling\u003dFalse, which Make_traffic_ctl does so the traffic_ctl\nconfig output is unchanged."
    },
    {
      "commit": "b55a391e3bd8ba143b9f9b0c266f72116c911570",
      "tree": "361128b64330182c995d9ba745b39d6d1c5e2a05",
      "parents": [
        "9580d3eba7379c85040f9d7899a6062f2ea69f47"
      ],
      "author": {
        "name": "Rayan-and-beyond",
        "email": "2220000455@iau.edu.sa",
        "time": "Wed Sep 30 08:00:57 2026 +0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 23:00:57 2026 -0600"
      },
      "message": "header_rewrite: fix empty CIDR fields (#13742)\n\nPreserve the documented default mask when either CIDR qualifier field is empty, while keeping explicit zero masks valid and rejecting malformed values. Add focused parser coverage and update the existing replay expectation.\n\nFixes: #13620"
    },
    {
      "commit": "9580d3eba7379c85040f9d7899a6062f2ea69f47",
      "tree": "3abdf7c5fe9a2950a0e3a1fcc868975652289740",
      "parents": [
        "839b3cb5bcbc18fff76c9d96ff760fc23217f36e"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Wed Sep 30 13:20:30 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 13:20:30 2026 +0900"
      },
      "message": "Bound cache directory bucket walks in all builds (#13608)\n\n* Bound cache directory bucket walks in all builds\n\nThe loop protection in probe/overwrite/remove/dir_clean_bucket sat\nbehind LOOP_CHECK_MODE, which is commented out and not settable from\nCMake, so production builds walked bucket chains unbounded. A cycle in\ndir_next spins an event thread while it holds the stripe mutex.\n\nDirectory::max_bucket_depth() is the bound, (DIR_DEPTH - 1) * buckets\n+ 1: init_segment() frees rows 1..DIR_DEPTH-1 of every bucket onto the\nfree list and never row 0, so one chain holds at most every free entry\nof the segment plus its own head. Exceeding it proves a cycle, so no\nexact check is needed at the trigger. bucket_length() capped at a\nhardcoded 100 instead, below the longest legitimate chain, so a chain\nover that would make check_segment() report corruption and\nStripe::_shm_directory_is_valid() reject a healthy shared memory\nattach.\n\nReaders report and move on, writers repair. probe() throttles its\nreport because it does not repair, so the loop lives until a writer\nclears it and every lookup that hashes to the bucket lands on the same\ntrigger. insert()\u0027s tail walk is the only chain walk it makes, so that\nis where a writer meets a cycle, and stopping at the cap linked the new\nentry into the cycle.\n\nStripe::dir_check() had no cap at all and wrote chain_tag[] once per\nstep, so a cycle ran off the end of a 65536-entry stack array. It now\nstops at the bound, and at the first revisited entry rather than\nprinting a cycle line per step. check_bucket_not_contains(), an\nunbounded walk with no caller since the 2009 import, is deleted.\n\n* Mark the cache directory dirty when wiping a segment\n\ninit_segment() clears a whole segment, but Directory::remove(),\nDirectory::overwrite(must_overwrite\u003dtrue) and dir_clean_bucket() all\nreturn straight after the bucket_loop_fix() repair, before the mutation\nthat would normally set the dirty flag. CacheSync::mainEvent() skips a\ndirectory whose dirty flag is clear, so the repair never reached disk\nand a crash brought the persisted loop back.\n\nThe flag belongs on init_segment() rather than bucket_loop_fix(): the\nwipe is the mutation, and the other caller, freelist_pop()\u0027s bad-freelist\npunt, was relying on insert()/overwrite() to retry and set the flag for\nit. That also covers the read-shaped callers, freelist_length(),\nentries_used() and make_vol_map(), which reach the repair too.\n\n* Account for the entries a segment reset discards\n\nbucket_loop_fix() and freelist_pop() wipe a whole segment through\ninit_segment(). The entries they discard stop existing without going\nthrough delete_entry(), so nothing ever takes them back off\ndirentries_used and the gauges stay inflated for the life of the\nprocess. Now that the repair runs from insert/overwrite/remove and\ndir_clean_bucket, that is reachable from the write path.\n\nThe count is taken over the segment\u0027s rows, not its chains, which are\ncorrupt wherever this runs. A null stripe means the caller is itself\nthe full scan that seeds the gauges, so the repair must leave them\nalone.\n\nAlso corrects the claim that a walk past max_bucket_depth() proves a\ncycle: a corrupted link into another bucket\u0027s row 0 builds an acyclic\nchain of up to DIR_DEPTH * buckets entries. The repair paths already\nconfirm the loop before wiping; only the comments were wrong. The new\ndir_check() test covers that case, which is the only one that reaches\nthe bound -- a looped chain trips the revisit detector first.\n\n* Never loop a bucket head in the CacheDir corruption helper\n\nBucket 0\u0027s head sits at offset 0, the end-of-chain sentinel, so pointing\nit at itself truncates the chain instead of looping it, and the repair\nassertions that follow fail intermittently."
    },
    {
      "commit": "839b3cb5bcbc18fff76c9d96ff760fc23217f36e",
      "tree": "86a531aa2ea840bbaa6038ecd652d3fbd6460ab7",
      "parents": [
        "17752c0709aff219a5e31b98b4ba1a3de090c9bd"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Wed Sep 30 08:01:42 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 08:01:42 2026 +0900"
      },
      "message": "cache: Move level-gated regression tests from traffic_server to Catch2 (#13741)\n\n* cache: port stripe hash stability test to Catch2\n\nThe regression version only ran at -R 3 and asserted nothing. Pin the\nproperty build_vol_hash_table guarantees: resizing one stripe moves\nslots only to or from that stripe.\n\n* cache: port LRU seen-filter threshold test to Catch2\n\nThe regression version was gated to -R 2, which CI never runs. Also\npin the below-threshold side so an always-on filter fails too.\n\n* cache: port RAM cache hit-rate test to Catch2\n\nThe ram_cache regression test was gated to -R 2, which CI never runs,\nso the hit-rate floor for LRU, CLFUS and S3-FIFO went unchecked.\n\n* tscore: define ts::Random state inline in the header\n\ntraffic_server links libtscore statically, so Random.cc.o was only\nexported to plugins while something in the core referenced it. Moving\nthe zipf test out of CacheTest.cc dropped the last such reference and\ncripts and cache_promote failed to load with an undefined\nts::Random::_state.\n\n* cache: address review comments on the ported tests\n\nA failed REQUIRE in the stripe hash test unwound past the cleanup, so\n~CacheHostRecord would ats_free() the stack stripe array; clear it\nright after each build instead. Also reword the seen-filter comment.\n\n* tscore: use a function-local thread_local for ts::Random\n\nDarwin clang emits the TLS wrapper of an inline thread_local variable\nas a strong symbol in every TU, so test_tscore failed to link on macOS\nwith a duplicate __ZTWN2ts6Random6_stateE. A function-local static is\nguarded instead and needs no wrapper.\n\n* cache: keep stripe directories small in the hash table test\n\nEach synthetic 911 GiB stripe allocated a ~1 GiB directory (31 GB\nvirtual, 1.3 GB resident for the test), which mattered once the test\nran under plain ctest. The hash table reads only len and hash_id, so\na huge average object size shrinks the directories without changing\nthe result."
    },
    {
      "commit": "17752c0709aff219a5e31b98b4ba1a3de090c9bd",
      "tree": "bbb12fd2ef9051730299c8edb3f596fe056286a1",
      "parents": [
        "a2416f28267b8f93c6b5ceaa065d5b6f25cc507d"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Tue Sep 29 17:26:08 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 17:26:08 2026 -0500"
      },
      "message": "Allow pull request auto-merge (#13752)\n\nMaintainers currently have to return to a pull request after its\nrequired checks and reviews finish to merge it manually.\n\nThis patch enables GitHub auto-merge through the ASF repository\nconfiguration so maintainers can schedule a merge while those\nrequirements are still pending.\n\nCo-authored-by: Codex GPT-6 Astra Medium"
    },
    {
      "commit": "a2416f28267b8f93c6b5ceaa065d5b6f25cc507d",
      "tree": "ef93734cdbfc6ed88eaaece4b84ca41dd66f4a06",
      "parents": [
        "4f176aceeb126a850400a9a301c88d162930dcb0"
      ],
      "author": {
        "name": "Masakazu Kitajo",
        "email": "maskit@apache.org",
        "time": "Mon Sep 28 16:27:57 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 16:27:57 2026 -0600"
      },
      "message": "Hex-encode non-alphanumeric ALPN bytes in JA4 fingerprints (#13719)\n\n* Hex-encode non-alphanumeric ALPN bytes in JA4 fingerprints\n\nThe first ALPN value in a ClientHello is an opaque byte string, but\nits bytes were copied verbatim into the unhashed section of the\nfingerprint. Follow the JA4 specification and use the hex\nrepresentation of that value when either end is not ASCII\nalphanumeric, so fingerprints agree with other implementations.\n\n* ja4_fingerprint: validate the ALPN extension before reading it\n\nThe first protocol name was sliced out of the extension using\nassertions rather than checks, so a short extension was mishandled and\na one-byte protocol name was rejected. Validate the payload length the\nway jax_fingerprint already does and yield no ALPN value when it does\nnot hold up.\n\n* Link the JA4 ALPN encoding comments to the specification"
    },
    {
      "commit": "4f176aceeb126a850400a9a301c88d162930dcb0",
      "tree": "9f9175664494c7d10fd5139f8e8d2977f4702e43",
      "parents": [
        "fb0733c57c86cda73d7de66958d23cf487d5cf78"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Mon Sep 28 14:58:54 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 14:58:54 2026 -0700"
      },
      "message": "Docs: add traffic shaping page and drop Confluence links (#13731)\n\nAdd an admin guide page on marking packets with SO_MARK and DSCP and\nshaping them with Linux tc, covering the socket option flags that enable\nmarking, the records.yaml settings, the plugin API, header_rewrite\noperators, pooled connection behavior, and connmark-based shaping of\nresponses. Point the records.yaml and packet marking API pages at it, and\nreplace the remaining links to the retired Confluence wiki and Jira with\nthe docs site, the GitHub wiki, GitHub issues, and the users mailing list."
    },
    {
      "commit": "fb0733c57c86cda73d7de66958d23cf487d5cf78",
      "tree": "da3fac8204526ce992192969d84897ab9473add3",
      "parents": [
        "a310157dd468342cef8ccda9827ab5ff92a0dcb3"
      ],
      "author": {
        "name": "Serris Santos",
        "email": "serrisnlew@gmail.com",
        "time": "Mon Sep 28 11:35:44 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 11:35:44 2026 -0700"
      },
      "message": "virtualhost.yaml with remap rules (#13108)\n\n* init vhost remap\n\n* Update doc from ssl_multicert.config to .yaml\n\n* Use new _reload directive\n\n* Update docs and tests\n\n* copilot reviews on docs, wildcard matching, empty vhost entry load\n\n* use shared_ptr, don\u0027t set global ip_allow flag\n\n* clear all, explicitly set remap_yaml\n\n* Add more config_reload_rpc tests\n\n* use rpc response instead of diags\n\n* Fix virtualhost validation, reload safety, and reload diagnostics\n\n* Serialize virtualhost full reload and refuse unsafe reloads\n\n* invalidate empty conf.id and group plugin reloads\n\n* Prevent mistyped directive key from doing full reload"
    },
    {
      "commit": "a310157dd468342cef8ccda9827ab5ff92a0dcb3",
      "tree": "08d37ec29dfb202e27ceb23a3e5133262d6a76d9",
      "parents": [
        "9a08e84831244211510d8dee6b7fd4cbb8347f65"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Mon Sep 28 09:52:58 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 09:52:58 2026 -0700"
      },
      "message": "txn_box: build the binary comparison type mask from the enum values (#13724)\n\nBase_Binary_Cmp::TYPES was built from a class-template static whose dynamic\ninitialization is unordered against it, so clang builds of txn_box.so got an\nempty mask and rejected every eq, ne, lt, le, gt and ge comparison. Build the\nmask directly from the supported value types, as Cmp_in already does, drop\nthe helpers that are now unused, and cover all six comparators with integer\nreplay tests."
    },
    {
      "commit": "9a08e84831244211510d8dee6b7fd4cbb8347f65",
      "tree": "14ddfdb26d40bbc689692996ded79b3d24c1fb64",
      "parents": [
        "4ad5081e9443f8f524b0fb313d7cf15932fbbc04"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Mon Sep 28 09:52:53 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 09:52:53 2026 -0700"
      },
      "message": "Scale the txn_box multi-ramp autest tolerance to the binomial spread (#13726)\n\nThe txn_box multi-ramp autests passed a bucket only when its count fell\nwithin plus or minus 5 percentage points of the ramp setting. At 30% that\nis just 3.45 standard deviations, so a working build failed about once in\n340 CI runs. A bucket now passes when its count is within 5 standard\ndeviations of the expected count, about one failure in 210,000 runs, and a\nmisrouted ramp still fails."
    },
    {
      "commit": "4ad5081e9443f8f524b0fb313d7cf15932fbbc04",
      "tree": "0e85ab2f70e34743fb52f853c2153c600c5caa88",
      "parents": [
        "ee427dbc5cb4acfbc4618d17fdf3562b57a4c04f"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Mon Sep 28 09:45:26 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 09:45:26 2026 -0700"
      },
      "message": "Initialize two locals Coverity reports as uninitialized (#13734)\n\nNeither is reachable as a defect, so this silences two false positives\nrather than fixing a read of an indeterminate value. Both are worth\ntaking because each is one word and each matches how the same code is\nalready written elsewhere in the tree.\n\nCID 1533658, plugins/background_fetch/configs.cc: every path that\nreaches the use of op assigns it, because the else branch of the\nthree-way condition calls TSError and continues. The analyzer cannot\nprove the chain is exhaustive. The copy of this function in\nplugins/experimental/cache_fill already carries the initializer.\n\nCID 1645841, src/proxy/http/remap/RemapYamlConfig.cc: entrylist is\nonly read after scandir returns a non-negative count, and POSIX stores\nthe array on success, so the free is safe. The legacy remap.config\nloop this was ported from, in RemapConfig.cc, initializes it to\nnullptr; the port dropped that."
    },
    {
      "commit": "ee427dbc5cb4acfbc4618d17fdf3562b57a4c04f",
      "tree": "e07a9f85385ccb685700199ea1755ff143bc73a1",
      "parents": [
        "c5ae69c8ea1bd399339337b09c73b202b3332724"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Mon Sep 28 11:37:27 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 11:37:27 2026 -0500"
      },
      "message": "Bind session ticket keys to the dest_ip certificate (#13736)\n\nSince #13677, every certificate context protects its session tickets\nwith the global ticket keys. For a client that sends no SNI, the\ncertificate is chosen by destination address, so a ticket issued on one\naddress now resumes on another address serving a different certificate,\nand the client is never shown that certificate. The per-context random\nkeys that #13677 removed were the only thing keeping those tickets\napart.\n\nThis patch derives the ticket key names, HMAC secrets and AES keys for\nan address with its own certificate context from the global keys and a\ndigest of that context\u0027s certificate. A ticket from another certificate\nthen matches no key and the client falls back to a full handshake,\nwhich ATS now records as such. Servers sharing the ticket key file and\nserving the same certificate derive the same keys, so they keep\nresuming each other\u0027s tickets as #13677 intended. Addresses without a\ncontext of their own use the global keys as before.\n\nOn a PROXY protocol port the certificate is chosen by the PROXY\ndestination address, so the ticket keys now follow that address too,\nwhich also stops an IPv6 PROXY destination being truncated before the\ncertificate lookup. A tunnel entry has no certificate by design and\nkeeps the global keys. Any other context whose keys cannot be bound to\na certificate neither issues nor accepts tickets, which a new counter\nand a throttled warning report. The unused per-context keyblock is\nremoved.\n\nFixes: #13735\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "c5ae69c8ea1bd399339337b09c73b202b3332724",
      "tree": "747946ca9b02c04b0cd4f21cb41058a64b4f5477",
      "parents": [
        "01cbbc51d2d854955463aa8dab714e19fe66730e"
      ],
      "author": {
        "name": "Masakazu Kitajo",
        "email": "maskit@apache.org",
        "time": "Mon Sep 28 10:04:29 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 10:04:29 2026 -0600"
      },
      "message": "Fix SSL 2.0 version code in JA4 fingerprints (#13728)\n\nThe ja4_fingerprint and jax_fingerprint plugins reported SSL 2.0 as\n\"s2\" for version 0x0200 and emitted an \"s1\" code for 0x0100, neither\nof which matches the JA4 spec. The spec maps 0x0002 to \"s2\" and has\nno SSL 1.0 code, so 0x0200 and 0x0100 now report \"00\" like any other\nunknown version."
    },
    {
      "commit": "01cbbc51d2d854955463aa8dab714e19fe66730e",
      "tree": "a27d35ff6a2f9943856440e854c4e0f8774c4356",
      "parents": [
        "738cd651b389bd32b4d0887f99d0a1960abc12b7"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Mon Sep 28 18:36:25 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 18:36:25 2026 +0900"
      },
      "message": "Coverity: avoid unsigned wrap in AIO cache_op loop (#13740)\n\naio_nbytes - res mixed size_t with ssize_t, so the remaining count was\nunsigned: a transfer that overshot aio_nbytes would wrap into a huge\nlength passed to pread/pwrite. Track progress as size_t and guard with\ndone \u003c aio_nbytes so the subtraction cannot underflow.\n\nCoverity CID: 1587281"
    },
    {
      "commit": "738cd651b389bd32b4d0887f99d0a1960abc12b7",
      "tree": "3cc97f572f9d9b99f22115f3f67c47297d56d06e",
      "parents": [
        "f5174f6bb80996c1d1d65e524e6a031d0ec62c72"
      ],
      "author": {
        "name": "Masakazu Kitajo",
        "email": "maskit@apache.org",
        "time": "Fri Sep 25 13:36:18 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 25 13:36:18 2026 -0600"
      },
      "message": "Include signature algorithms in JA4 fingerprints (#13725)\n\n* Include signature algorithms in JA4 fingerprints\n\nThe ja4_fingerprint and jax_fingerprint plugins hashed only the\nextension list for the last section of a JA4 fingerprint and left out\nthe client\u0027s signature algorithms, which the JA4 spec requires. Nearly\nevery real client sends them, so the fingerprints never matched those\nfrom other JA4 tools. Both plugins now follow the spec, and the spec\u0027s\nown example is covered by unit tests.\n\nThis changes the last section of almost every JA4 fingerprint the\nplugins produce. Stored fingerprints and any rules or allow/deny lists\nbuilt from them need to be regenerated.\n\n* Test JA4 signature algorithms on a live ClientHello\n\nThe unit tests feed signature algorithm bytes to the fingerprint code\ndirectly, so they would still pass if jax_fingerprint stopped reading\nthe extension from the ClientHello. This AuTest connects with different\nsignature algorithm lists and orders and checks that only the last\nsection of the JA4 fingerprint changes."
    },
    {
      "commit": "f5174f6bb80996c1d1d65e524e6a031d0ec62c72",
      "tree": "f1719de8b5b1f1685e24277989034e316820d91d",
      "parents": [
        "c790311235147c1e9e59ea6169213041c44b138e"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Thu Sep 24 11:50:02 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 24 11:50:02 2026 -0700"
      },
      "message": "Make the origin session cache size limit configurable (#13711)\n\nSSLOriginSessionCache::insert_session() silently dropped any origin TLS session\nwhose serialized form exceeded a fixed 4096 bytes, a size real origins pass;\nmTLS sessions measured 5463 bytes, giving zero cache hits. Replace the limit\nwith proxy.config.ssl.origin_session_cache.max_session_size, default 8192,\nclamped to 4096-65536 because it also sizes the alloca in SSLSessionDup()."
    },
    {
      "commit": "c790311235147c1e9e59ea6169213041c44b138e",
      "tree": "4a7849db0c88b0166c78d5cdd83491a29283f1f9",
      "parents": [
        "e32c31f81c547ce9eac481962377dcb85fc951a1"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Thu Sep 24 12:10:36 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 24 12:10:36 2026 -0500"
      },
      "message": "header_rewrite: reject incomplete config lines (#13650)\n\nA header_rewrite configuration line containing only modifiers, or a\ncond keyword without an operand, can leave the parser indexing an\nempty token list. Malformed configuration can therefore crash Traffic\nServer during plugin initialization.\n\nThis patch rejects empty token lists after consuming modifiers or the\ncond keyword, allowing the caller to log and skip the invalid lines.\nUnit tests cover bare cond and short and long modifier tokens, while\nan AuTest verifies that ATS starts, logs the errors, and applies the\nremaining valid rules.\n\nFixes: #13639\n\nCo-authored-by: Claude Opus 5\nCo-authored-by: GPT-6 Astra Medium"
    },
    {
      "commit": "e32c31f81c547ce9eac481962377dcb85fc951a1",
      "tree": "1b2f598eafb06459d5cfb01db56be0e4b99a5f86",
      "parents": [
        "b63c370e88b3db912013b4494a72c68edb89293e"
      ],
      "author": {
        "name": "Masakazu Kitajo",
        "email": "maskit@apache.org",
        "time": "Wed Sep 23 10:03:02 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 23 10:03:02 2026 -0600"
      },
      "message": "tests: cover the global TLSv1.3 session ticket count (#13717)\n\nproxy.config.ssl.server.session_ticket.number had no coverage for a\nnonzero value. The existing ticket tests either set it and assert only\nTLSv1.2 reuse, or assert counts that come from the sni.yaml override."
    },
    {
      "commit": "b63c370e88b3db912013b4494a72c68edb89293e",
      "tree": "8f3cdc3905fc5c5f5a09064b86086cf6a68090f4",
      "parents": [
        "3e10681a9e0b863dbc86ea0655a2c57920b35cbd"
      ],
      "author": {
        "name": "Mo Chen",
        "email": "mochen@apache.org",
        "time": "Wed Sep 23 09:01:00 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 23 09:01:00 2026 -0500"
      },
      "message": "Stabilize the rate_limit SNI expiry AuTest (#13721)\n\n* Stabilize the SNI queue expiry test\n\nOpen the FIFO before forking clients so cleanup cannot race their\nstartup. Wait for limiter events instead of fixed sleeps so the expiry\npath is exercised reliably on loaded runners.\n\nFixes: #13714"
    },
    {
      "commit": "3e10681a9e0b863dbc86ea0655a2c57920b35cbd",
      "tree": "85b6cfb14ce9b833ca625c7b0c18849980983836",
      "parents": [
        "f9c2f08fbcf09048bd9d6651aba656934d70d862"
      ],
      "author": {
        "name": "Chris McFarlen",
        "email": "chris@mcfarlen.us",
        "time": "Tue Sep 22 18:17:23 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 18:17:23 2026 -0500"
      },
      "message": "cache: retry without O_DIRECT for an explicit file span (#13718)\n\nThe non-direct-IO retry added in TS-1312 only fires when O_CREAT is\nset, and O_CREAT is set only when the span names a directory, so that\ncache.db can be created inside it. An explicit file span in\nstorage.config therefore gets no retry: on a file system without\nO_DIRECT support the span open fails outright and the cache is\ndisabled, even though the very same file system works when the span is\nwritten as a directory. Whether direct I/O is usable is a property of\nthe file system, not of the form the span was written in.\n\nThe cache_shm_* autests are the only ones configuring an explicit file\nspan, so on a sandbox whose file system lacks O_DIRECT all of them\nfail with \"must be placed on a file system that supports direct I/O\"\nfollowed by \"Cache Disabled\"."
    },
    {
      "commit": "f9c2f08fbcf09048bd9d6651aba656934d70d862",
      "tree": "872ef5cc343cb9cd1ed0cfa0838e3aafdf829fec",
      "parents": [
        "0079038a12a9f1b6a71c8c4b5e97b953ea7c4663"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Tue Sep 22 18:02:26 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 18:02:26 2026 -0500"
      },
      "message": "Fix reuse of origin sessions attached to the client (#13713)\n\nWith proxy.config.http.attach_server_session_to_client enabled, the\norigin session attached to a keep-alive client session was closed as\nsoon as the transaction finished. Every subsequent request on that\nclient connection therefore opened a new origin connection, and the\n%\u003csstc\u003e log field always reported no reuse. The detach in\nHttpSM::kill_this, added to avoid a use-after-free on that closed\nsession, masked the problem rather than fixing it.\n\nThis patch keeps an attached (KA_RESERVED) origin session open when its\ntransaction completes, leaving it owned by the client session, and\nteaches Http1ServerSession::release() to pool or close the session when\nthe client session later gives it up. With the session no longer\nclosed out from under the client, the detach in kill_this is removed so\nthe next transaction can reuse the attached session.\n\nThis patch also adds an autest that sends several requests over one\nclient connection and verifies that sstc increments across them.\n\nFixes: #9149\n\nCo-authored-by: Claude Opus 5.5 (medium reasoning) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "0079038a12a9f1b6a71c8c4b5e97b953ea7c4663",
      "tree": "8bc492a5a06a121a6f0987fbca87827d539a5513",
      "parents": [
        "e215a813247bdec5bd4a1cc4bb83dff1a72d498f"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Tue Sep 22 16:56:32 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 16:56:32 2026 -0500"
      },
      "message": "Test 103 Early Hints before a cached range response (#13715)\n\nIssue #12244 reported ATS aborting on the HttpTunnel skip_bytes\nassertion for Range requests of a small, cacheable 308. The fix in\n#12906 was tested only with a 100 Continue ahead of a compressed POST\nresponse, so the reported scenario had no coverage. 103 Early Hints\ntake the same interim-response path as 100 Continue, and a Range miss\nwith cache.range.write enabled caches the untransformed response behind\nthe range transform, leaving the cache-write consumer with a stale\nheader size to skip in a body-only buffer.\n\nThis patch extends the regression test with a run in which the origin\nsends a 103 Early Hints and then a 65 byte, cacheable 308 that the\nclient requests with \"Range: bytes\u003d0-64\". Without the #12906 fix, this\nrun hits the same assertion reported in the issue; with it, ATS keeps\nrunning.\n\nFixes: #12244\n\nCo-authored-by: Claude Opus 5.5 (Medium effort) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "e215a813247bdec5bd4a1cc4bb83dff1a72d498f",
      "tree": "89aa0c8f0836c9567a1a3ab685a63f5fe17948d2",
      "parents": [
        "f39ee5f5b78722252689c23a46fadd577a2a95ea"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Tue Sep 22 15:37:21 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 15:37:21 2026 -0500"
      },
      "message": "clang-tidy: modernize-use-using (#13613)\n\nLegacy typedef declarations obscure complex aliases and preserve C-era\ndeclaration patterns in ATS and its plugins.\n\nThis patch replaces the existing findings with named C++ declarations or\nusing aliases and enables the check in CI to keep new code consistent.\nStruct definitions use their intended names directly to avoid redundant\naliases.\n\nCo-authored-by: Codex Astra Medium"
    },
    {
      "commit": "f39ee5f5b78722252689c23a46fadd577a2a95ea",
      "tree": "ae6c994eb826db8b3f110ad691bc113aed743a1b",
      "parents": [
        "493bc01d1b8ee412507f2776f0e8a702fb99686d"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Tue Sep 22 15:22:26 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 15:22:26 2026 -0500"
      },
      "message": "Handle all cachekey regex capture groups (#13653)\n\nCachekey patterns with ten or more capture groups can crash ATS when\nbuilding a cache key because a successful match leaves the capture\nvector empty. Replacement patterns also reject valid group references\nwhen the match buffer is too small or trailing optional groups do not\nparticipate in a match.\n\nThis patch sizes match buffers from the validated pattern capture count\nand checks replacement references at initialization. Unmatched optional\ngroups contribute empty strings. Unit and replay coverage verifies full\ncache keys across the capture limit and optional-group combinations.\n\nFixes: #13638\n\nCo-authored-by: GPT-6 Astra Light\nCo-authored-by: GPT-6 Astra Medium\n\nCo-authored-by: bneradt \u003cbneradt@yahooinc.com\u003e"
    },
    {
      "commit": "493bc01d1b8ee412507f2776f0e8a702fb99686d",
      "tree": "e36383ebf9309ab01ae75d4599701b773c19b56d",
      "parents": [
        "7d1582611a515b6f6f73e9397aa97258a38b4b84"
      ],
      "author": {
        "name": "Phong Nguyen",
        "email": "phongn@gmail.com",
        "time": "Tue Sep 22 11:00:04 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 13:00:04 2026 -0500"
      },
      "message": "Honor the RamCache copy flag in LRU and S3-FIFO (#13380)\n\nCacheVC requests copy semantics (put copy\u003dtrue) whenever RAM cache\ncompression is configured, because it unmarshals HTTP headers in place\nin its own buffer after the put and again on every RAM hit. LRU and\nS3-FIFO ignored the flag and shared buffers with the caller in both\ndirections, so with proxy.config.cache.ram_cache.compress enabled and\nalgorithm\u003d1 (the default) or 2, the cached bytes were mutated after\ninsertion and every subsequent HTTP RAM hit re-unmarshalled an\nalready-unmarshalled header (assert in debug builds, header unmarshal\nfailure in release). Copy entries now copy on put, copy on get, and a\ncopy\u003dtrue put refreshes a resident entry that may still be sharing a\ncaller\u0027s buffer, matching CLFUS.\n\nCo-Authored-By: Claude Fable 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "7d1582611a515b6f6f73e9397aa97258a38b4b84",
      "tree": "cb8d425ccfb07413453136e93f1fe7652c646366",
      "parents": [
        "ca133303832de2cb0c1d5b2ea38c9d2cc5d53820"
      ],
      "author": {
        "name": "Jake",
        "email": "jake.champion@netlify.com",
        "time": "Tue Sep 22 13:59:07 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 07:59:07 2026 -0500"
      },
      "message": "Wrap cache key generation in `HttpSM` helpers (#13706)\n\nEvery cache key call site had to repeat the same two `txn_conf` arguments, which makes it easy for a new call site to pass a different `ignore_query` or generation number and silently compute a key that does not match the rest of the transaction. Funnel them\nthrough `generate_cache_key()`/`generate_ cache_key92()` instead."
    },
    {
      "commit": "ca133303832de2cb0c1d5b2ea38c9d2cc5d53820",
      "tree": "567a3166f915a69695b34e579cab02f4310a8293",
      "parents": [
        "2651038e6faa5312b190f49c515f600794de67cc"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Tue Sep 22 21:00:45 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 21:00:45 2026 +0900"
      },
      "message": "hrw4u: enforce sandbox NOT and in on their implicit spellings (#13675)\n\n* hrw4u: enforce sandbox NOT and in on their implicit spellings\n\n`modifiers: [NOT]` only caught an explicit `with NOT`, and\n`language: [in]` only caught the `[...]` value form, so `!expr`, `!\u003d`,\n`!~`, `!in` and `in {10.0.0.0/8}` all compiled unchecked. AND and OR\nwere already checked at `\u0026\u0026` and `||`; negation and IP-range membership\nare now consistent with that.\n\nThe check sits at the two sites where the source introduces negation,\nnot at `_make_condition`, whose `negate` argument is also true for the\n`[NOT]` the compiler synthesises for a bare header test. Denying `NOT`\nmust not reject `if inbound.req.X-Foo`; allowed-implicit-not pins that.\n\n`modifiers` was undocumented, so the sandbox section gains it.\n\n* Address review: name the tag the compiler actually emits\n\nThe modifiers example said `%{HEADER:X-Foo}`, but `inbound.req.X-Foo`\nlowers to CLIENT-HEADER, as allowed-implicit-not\u0027s golden output shows.\nKept the literal on one line while here.\n\n* Address review: cover the !~ spelling of NOT\n\nNOT_TILDE is its own lexer token; without a case for it, dropping it\nfrom the negate tuple still passed."
    },
    {
      "commit": "2651038e6faa5312b190f49c515f600794de67cc",
      "tree": "c07612f209d5f727373131f5b3ec48cf3d259f2a",
      "parents": [
        "915543f9a5ceb0b8255413d63682ed9247a60543"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Tue Sep 22 20:59:41 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 20:59:41 2026 +0900"
      },
      "message": "hrw4u: add an AST round-trip test over the whole corpus (#13699)\n\n* hrw4u: add an AST round-trip test over the whole corpus\n\nRender every corpus input\u0027s AST back to hrw4u and require the compiled\nconfig to be unchanged: whatever the AST drops, the config loses too.\nUnlike hand-written cases, nothing has to be enumerated in advance.\n\nIt found five losses, all fixed here:\n\n  - an empty `else { }` looked like no else clause, so a sandbox policy\n    denying \u0027else\u0027 was evaded by writing one\n  - comments were discarded, though five .conf goldens carry them\n  - a bool assignment lost the spelling the emitter echoes back\n  - parentheses were unwrapped, dropping the cond %{GROUP} they emit\n  - a set and an iprange both became a tuple of IPValue, though\n    in [1.2.3.4] emits (1.2.3.4) and in {1.2.3.4} emits {1.2.3.4}\n\nIfBlock.has_else is required rather than defaulted, so a site that\nrebuilds the node and forgets it fails instead of reopening the bypass.\n\nA second test asserts the corpus reaches every grammar rule; a bare\n$param value had no fixture, now added.\n\n* hrw4u: keep bool spelling in every value context\n\nThe AST kept the source spelling only on an assignment RHS, so a TRUE\nin a comparison or a function argument regenerated as true and changed\nthe emitted config. bool-spelling.input.txt witnesses both; the reverse\nnormalizes an argument\u0027s spelling, hence the exceptions.txt entry.\n\n* hrw4u: keep number spelling in every value context\n\nThe AST parsed a NUMBER into a Python int, so a leading zero the emitter\nechoes back was lost: 007 became 7 in a header value, three bytes\nbecoming one. number-spelling.input.txt witnesses all three value\ncontexts; the digits survive in each.\n\nA plain int was a deliberate call, on the grounds that no corpus input\nwrote a leading zero. It did not survive a semantic pass built on the\nAST, which matches structurally over ValueExpr and has nowhere to put a\nnaked int.\n\n* hrw4u: make the per-test sandbox fixture compile\n\nIts body wrote inbound.req.X-Foo inside TXN_START, where that field does\nnot exist, so the input was rejected before the sandbox ran and the\nround-trip test had to name it as the one corpus input that does not\ncompile. The fixture only ever asserted that a per-test sandbox.yaml is\npreferred over the shared one, and a section denial fires whatever the\nbody is, so the body is now a rule TXN_START actually admits.\n\nThat retires DOES_NOT_COMPILE: an input meant to be rejected is named\n.fail., and a corpus input that stops compiling should fail the test\nrather than opt out of it."
    },
    {
      "commit": "915543f9a5ceb0b8255413d63682ed9247a60543",
      "tree": "ed5c1cdf44e1bdb9aab7684c698556ce2ea5ea4e",
      "parents": [
        "bfe88e104a2bb174220f525436e148c45145f845"
      ],
      "author": {
        "name": "Masaori Koshiba",
        "email": "masaori@apache.org",
        "time": "Tue Sep 22 20:57:40 2026 +0900"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 20:57:40 2026 +0900"
      },
      "message": "hrw4u: exit non-zero on compile errors (#13656)\n\n* hrw4u: exit non-zero on compile errors\n\nThe exit gate required `tree is None`, but ANTLR error recovery almost\nalways yields a tree, so both syntax and semantic errors exited 0 while\nprinting diagnostics and a partial .conf. Collecting every error and\nfailing the build were mutually exclusive: only --stop-on-error exited 1.\nSandbox denials were caught by the same gate, so the \"denied\" outcome the\nsandbox docs describe also exited 0.\n\ngenerate_output now reports failure by return value and run_main owns the\nexit, so a bad file in a bulk run no longer aborts the files after it.\n\nA failing compile still prints its partial .conf; the exit code now marks\nit untrustworthy. Suppressing those bytes would change behavior for\nexisting pipelines and is left as a separate decision.\n\n* hrw4u: parse real input in generate_output return-value tests\n\nThe failure test passed parser_obj\u003dNone, which only worked because a\nNone tree short-circuits before the AST branch reads it. Parsing a real\ninput instead also pins the regression: the input parses, so the tree is\nnot None -- exactly what the old exit gate let through.\n\n* hrw4u: cover u4wrh in the exit-code tests, scope the doc claim\n\nu4wrh drives the same run_main(), so the contract regresses just as\neasily there; verified the new test exits 0 against the pre-fix code.\n\nThe doc said every input is processed before the status is decided,\nwhich reads as covering the fatal argument and I/O paths too -- those\nstill exit immediately.\n\n* hrw4u: document exit status 2 for usage errors\n\nrun_main() lets argparse handle the command line, so an unknown option,\na bad option value, or conflicting output modes exit 2, not the 1 the\ntable claimed. Normalizing them to 1 would merge \"you typed the command\nwrong\" into \"your rules did not compile\", so the doc follows the code.\n\nRow 1 now lists only what actually exits 1; the mixed bulk/stdout\nrejection is caught after parsing and belongs there, not with argparse."
    },
    {
      "commit": "bfe88e104a2bb174220f525436e148c45145f845",
      "tree": "3c8a1f4815402a6eb7596bad9333bc03f625025f",
      "parents": [
        "f753de1d46917c5f26ed565d43d1b7be1a8c1b7f"
      ],
      "author": {
        "name": "Damian Meden",
        "email": "dmeden@apache.org",
        "time": "Tue Sep 22 09:52:57 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 09:52:57 2026 +0200"
      },
      "message": "QPACK: use || in the varint decode range guards (#13655)\n\nTen guards in QPACK.cc read\n`xpack_decode_integer(...) \u003c 0 \u0026\u0026 value \u003e 0xFFFF`, so neither condition\nrejects anything: a decode failure falls through, and an oversized\nvarint is silently narrowed into the surrounding uint16_t. The\ndelta_base_index guard also had its comparison inverted.\n\nThe unchecked failure matters more than the truncation. On failure\nxpack_decode_integer returns -1, and callers then do `read_len +\u003d ret`,\ngiving SIZE_MAX. IOBufferReader::consume() takes that as -1, its\nrelease-assert passes because is_read_avail_more_than(-2) is true, and\nstart_offset moves backwards. The helper returns 0 rather than a\nnegative, so _on_encoder_stream_read_ready() does not abort and its\n`while (is_read_avail_more_than(0))` loop re-reads the same byte.\n\nFlip the ten operators and correct the inverted comparison.\n\nThe value guard in _read_insert_with_name_ref also has its bound raised\nfrom 0xFF to 0xFFFF, matching the other nine sites. This is required\nrather than cosmetic: value_len is a size_t, so 0xFF bounds nothing, and\nunder || a 0xFF bound would reject every header value longer than 255\nbytes. At 0xFFFF the check is unreachable, since xpack_decode_string is\nalready capped by _header_field_max_size."
    },
    {
      "commit": "f753de1d46917c5f26ed565d43d1b7be1a8c1b7f",
      "tree": "7a77c1e6fafe32be34f15fd54822b41df5b64ada",
      "parents": [
        "756254f902a45c474316163444173335b19ce72c"
      ],
      "author": {
        "name": "Damian Meden",
        "email": "dmeden@apache.org",
        "time": "Tue Sep 22 09:51:45 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 09:51:45 2026 +0200"
      },
      "message": "HTTP/3: compare stream ids at full width in HQSession lookup (#13635)\n\n* HTTP/3: compare stream ids at full width in HQSession lookup\n\nHQSession::get_transaction() matched with\nt-\u003eget_transaction_id() \u003d\u003d static_cast\u003cint\u003e(id). get_transaction_id()\nreturns int and QUICStreamId is a 62-bit value, so both sides narrow and\ntwo live transactions whose ids share the low 32 bits alias each other.\n\nAdd get_quic_stream_id(), returning the QUICStreamId already cached in\n_stream_id by the constructor, and compare against that. Reaching\nthrough _info.adapter.stream() instead would reintroduce the\nuse-after-free fixed by 13213.\n\n* HTTP/3: move get_quic_stream_id() to the HQTransaction block\n\nThe declaration sat under \"Implement ProxyClienTransaction interface\",\nbut get_quic_stream_id() is not a ProxyTransaction override. Move it\nnext to direction(), after it so the alignment group on\nstate_stream_open/state_stream_closed/direction is untouched.\n\nDeclaration placement only; no behavior change."
    },
    {
      "commit": "756254f902a45c474316163444173335b19ce72c",
      "tree": "16e19caf6dcd286aab9989c0cb1e5005fe70604d",
      "parents": [
        "edb8476acc3466876320fd70ca9ff12f34d1f6d0"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Mon Sep 21 22:04:03 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 22:04:03 2026 -0700"
      },
      "message": "Fix cache_fill range request detection and a Content-Length config gap (#13704)\n\nBgFetchConfig::bgFetchAllowed() looked for the Range and conditional headers\nwith a misplaced paren, so header.size() \u003d\u003d TS_SUCCESS passed a length of zero\nand the returned MIMEFieldSDKHandle was used in boolean context and dropped.\nDetection still worked, because hdrtoken_is_wks() never consults the length,\nbut every matching request leaked a handle and an assert-enabled build aborted\non ink_assert(!field_name.empty()). Pass the name length, test the handle and\nrelease it. Also reject a Content-Length condition carrying no size, which\nbackground_fetch already does: without it the parsed and source views are both\nempty, the size guard compares 0 to 0, and a \u003c\u003d 0 rule is installed from a line\nthat specified no size."
    },
    {
      "commit": "edb8476acc3466876320fd70ca9ff12f34d1f6d0",
      "tree": "4c57a9c97dc32723b2872826d8b017fc7664c76e",
      "parents": [
        "62bda5a58595a798b0867c631dcb0b01bc08985f"
      ],
      "author": {
        "name": "Bryan Call",
        "email": "bcall@apache.org",
        "time": "Mon Sep 21 21:15:57 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 21:15:57 2026 -0700"
      },
      "message": "Handle HTTP/2 1xx interim responses from the origin (#13351)\n\nATS mishandled 1xx interim responses on an outbound HTTP/2 connection. The\ninterim headers decoded into the same buffer as the final response, producing a\nduplicate :status that failed validation, so ATS reset the stream and returned a\n502 while the origin was still there. A 1xx status is now detected after decode\nand discarded, and one carrying END_STREAM returns a stream PROTOCOL_ERROR per\nRFC 9113 8.1 rather than hanging the client. CONTINUATION is accepted on an\noutbound stream in half-closed (local), and rcv_continuation_frame() starts a\ntransaction only for a new inbound request: relaxing that state reached an\ninbound-only new_transaction(), whose ink_release_assert(_sm \u003d\u003d nullptr) aborted\ntraffic_server for any origin splitting a header block across frames."
    },
    {
      "commit": "62bda5a58595a798b0867c631dcb0b01bc08985f",
      "tree": "612c94fc8e6c30026ca4e7fabcc56379dd48b8fb",
      "parents": [
        "70c6b2c40a2026f1d47f18f81b39267e96752454"
      ],
      "author": {
        "name": "Phong Nguyen",
        "email": "phongn@gmail.com",
        "time": "Mon Sep 21 15:19:38 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 15:19:38 2026 -0700"
      },
      "message": "Add lz4 and zstd compression support to the CLFUS RAM cache (#13257)\n\nCo-authored-by: Claude Fable 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "70c6b2c40a2026f1d47f18f81b39267e96752454",
      "tree": "5f9d3f82b6e6ec5beeb829b7e54d416c53990bb5",
      "parents": [
        "a3760c4065c044419b419d422e69d09cbb42071d"
      ],
      "author": {
        "name": "Phong Nguyen",
        "email": "phongn@gmail.com",
        "time": "Mon Sep 21 15:18:20 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 15:18:20 2026 -0700"
      },
      "message": "Use __atomic builtins as the freelist 128-bit CAS fallback (#13571)\n\nPlatforms without an inline 128-bit CAS, such as riscv64, fail the\nbuild with \"unsupported processor\". Neither GCC nor LLVM emit an\ninline 128-bit CAS on riscv64, even with the Zacas extension, so a\nhand-written pointer-packing branch would be the only alternative\nand would depend on the kernel\u0027s virtual address width. Fall back\nto the __atomic builtins instead. They lower to libatomic calls,\nwhich may take internal locks; that is correct because every access\nto a shared head_p goes through INK_QUEUE_LD and ink_atomic_cas.\n\nAlso revive the orphaned atomic list stress test as Catch2 tests\nand remove the dead INK_QUEUE_NT code.\n\nFixes: #13555\n\nCo-Authored-By: Claude Fable 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "a3760c4065c044419b419d422e69d09cbb42071d",
      "tree": "15d771e203e2e1fec84b66f21406e9f10ed577bb",
      "parents": [
        "9c69fe1bcc7b76cce54525458c6efb17efc7b826"
      ],
      "author": {
        "name": "Phong Nguyen",
        "email": "phongn@gmail.com",
        "time": "Mon Sep 21 15:17:29 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 15:17:29 2026 -0700"
      },
      "message": "Apply the LRU seen filter to new keys only (#13669)\n\nLRU ran the seen filter before looking the key up, so a put for a\nresident entry, and a put replacing a stale copy of the key under a new\nauxkey (a rewrite), were each declined once: the first loses its recency\nbump, the second costs a second disk read. Look the key up first and\nfilter only keys the cache does not hold, which is the result CLFUS\u0027s\npersistent fingerprint already gives.\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "9c69fe1bcc7b76cce54525458c6efb17efc7b826",
      "tree": "6d3047528c95236fbef468f8f916f7e0a9eda2bd",
      "parents": [
        "7e4a7637c01fb1455921b1e5e99182847fc04731"
      ],
      "author": {
        "name": "Jake",
        "email": "jake.champion@netlify.com",
        "time": "Mon Sep 21 23:13:51 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 15:13:51 2026 -0700"
      },
      "message": "fix cancel/accept race in NetAccept that causes EBADF abort (#13702)\n\nNetAcceptAction::cancel() closes the server socket before setting the cancelled flag\nIn the window between close and flag set, net_accept() can get EBADF from accept4(), see cancelled\u003dfalse, and dispatch\nEVENT_ERROR to handlers that don\u0027t expect it\n\nnow we check the atomic server pointer in all three accept paths before dispatching EVENT_ERROR"
    },
    {
      "commit": "7e4a7637c01fb1455921b1e5e99182847fc04731",
      "tree": "e644545c34aa9708d28eab5fa8ef104717747af8",
      "parents": [
        "0609db12a9026d2522fdce3c25500d042f1bd22e"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Sep 21 15:06:56 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 15:06:56 2026 -0700"
      },
      "message": "build(deps): bump anyio from 4.13.0 to 4.14.2 in /tools/changelog (#13707)\n\nBumps [anyio](https://github.com/agronholm/anyio) from 4.13.0 to 4.14.2.\n- [Release notes](https://github.com/agronholm/anyio/releases)\n- [Commits](https://github.com/agronholm/anyio/compare/4.13.0...4.14.2)\n\n---\nupdated-dependencies:\n- dependency-name: anyio\n  dependency-version: 4.14.2\n  dependency-type: indirect\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "0609db12a9026d2522fdce3c25500d042f1bd22e",
      "tree": "47035941c1ef4685bdb8777a96186681bd0a246c",
      "parents": [
        "6cc6a2d150b5631d6b3d7aa82d52e687a2e250ff"
      ],
      "author": {
        "name": "Damian Meden",
        "email": "dmeden@apache.org",
        "time": "Mon Sep 21 20:18:29 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 20:18:29 2026 +0200"
      },
      "message": "test_rpcserver: scope handler registration to the test case (#13649)\n\n* test_rpcserver: scope handler registration to the test case\n\nA failing assertion inside a SECTION reports twice. Catch2 re-runs the\nTEST_CASE body once per SECTION, and the trailing test_remove_handler()\nnever runs when a fatal REQUIRE unwinds first, so the handler survives\ninto the next run and its add_method_handler() fails as well. The second\nfailure points at a registration that was never the problem.\n\nTie registration to a scope guard instead, so the handler is removed on\nthe way out however the body exits. The concurrent-request case never\nremoved its two handlers at all, and never checked that registering them\nworked; it uses the guard now as well."
    },
    {
      "commit": "6cc6a2d150b5631d6b3d7aa82d52e687a2e250ff",
      "tree": "c4c29795e5e8fc0eab2fa1232ee232845268457f",
      "parents": [
        "7741a2b237afa315782a2aa287df2f47d5cdf020"
      ],
      "author": {
        "name": "Damian Meden",
        "email": "dmeden@apache.org",
        "time": "Mon Sep 21 20:17:12 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 20:17:12 2026 +0200"
      },
      "message": "traffic_ctl: emit JSON null instead of YAML tilde (#13609)\n\n* traffic_ctl: emit JSON null instead of YAML tilde\n\nThe JSON encoders are yaml-cpp emitters, and yaml-cpp spells null as\n`~`, so any RPC payload holding a null value was rejected by every\nJSON parser. `hostdb status` hit this on every freshly started server\nand still exited 0, so callers saw success and then failed to parse.\n\nInitialise the two accumulator nodes as sequences so an empty result\nis `[]` rather than null, which also satisfies the published schema,\nand set LowerNull on the four JSON emitters so any remaining null is\nspelled `null`. Both spellings parse back as null in YAML, so the\nserver\u0027s ability to accept YAML input is unaffected."
    },
    {
      "commit": "7741a2b237afa315782a2aa287df2f47d5cdf020",
      "tree": "d2fd8a555e4073110e18caca06805b224cff2905",
      "parents": [
        "26a392178a30334f09e6cb06b395f021a1eec6ff"
      ],
      "author": {
        "name": "Brian Neradt",
        "email": "brian.neradt@gmail.com",
        "time": "Mon Sep 21 10:38:26 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 10:38:26 2026 -0500"
      },
      "message": "Allow WKS table changes without invalidating caches (#13603)\n\nThe well-known string table could not be reordered or extended freely\nbecause cached headers persisted indexes into it. Changing the table could\nmake existing objects report the wrong method or scheme and hide fields\nfrom header lookups. This blocked the string-table cleanup in #9636.\n\nThis patch removes that constraint by rebuilding indexes from the strings\nalready stored in each cached object whenever its WKS identity is absent\nor differs from the reader\u0027s. Matching identities avoid the rebuild.\nFuture builds can therefore change the table\u0027s indexes and cardinality\nwhile continuing to serve existing disk and compressed RAM-cache entries.\n\nThis patch also makes cache version bumps safe by selecting fragment\ndecoders against a fixed layout boundary. Cache scans and offline\ninspection support the same compatibility rules, and malformed headers\nare rejected. Version 24.3 preserves existing caches on upgrade while\nmaking older readers refetch newly written objects on rollback. Tests\ncover legacy layouts, identity matching, and index reconstruction.\n\nRelated: #9636\n\n---------\n\nCo-authored-by: bneradt \u003cbneradt@yahooinc.com\u003e\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nCo-authored-by: GPT-6 Astra Medium\nCo-authored-by: jake champion \u003cjake.champion@netlify.com\u003e"
    },
    {
      "commit": "26a392178a30334f09e6cb06b395f021a1eec6ff",
      "tree": "b84ece1ef277e3601801e4d75b0f11304ed966b6",
      "parents": [
        "37009bf1b2bb5f897c89699bc01c06bd6b20002a"
      ],
      "author": {
        "name": "Brian Olsen",
        "email": "brian_olsen2@comcast.com",
        "time": "Sun Sep 20 22:48:52 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 20 22:48:52 2026 -0600"
      },
      "message": "Make the 9.2 compatibility cache key usable end to end (#13611)\n\nproxy.config.http.cache.try_compat_key_read could find an object under\nthe previous key but not maintain one: revalidating it could never\nsucceed, since a 304 cannot be applied to a vector the current key does\nnot address, and invalidations left the old copy behind. Revalidate a\nlegacy object\u0027s GET without conditional headers so the full response\nis stored under the current key, keeping HEAD and range requests\nconditional since neither response is stored. Send invalidations to\nboth keys, serve a plugin update of a legacy object without storing\nit, and document what enabling the setting costs.\n\nDeletes now address the URL the lookup used rather than\ncache_info.lookup_url, which does not track a redirect follow when the\npristine host header is kept. A purge on a redirect-followed\ntransaction therefore removes the object that was looked up. This\napplies with the compatibility key off as well."
    }
  ],
  "next": "37009bf1b2bb5f897c89699bc01c06bd6b20002a"
}
