)]}'
{
  "log": [
    {
      "commit": "cb38b30ab8800c56cbe95f17d2a8f267d074f819",
      "tree": "fcd1c8af047fc708d58400164fabe53f240d2bc5",
      "parents": [
        "4c831c7fae2b51da926f883cb6f647f76c7259ba"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Thu Oct 29 17:59:37 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 17:59:37 2026 +0800"
      },
      "message": "Analyze OTLP spans opt-in by service.layer, and file the OTLP service catalog by layer (#14170)\n\nTAL is opt-in by layer:\n- The shipped tal/otlp-general.yaml (was otlp-default.yaml) declares\n  its rules for OTLP_GENERAL (renamed from OTLP_SERVICE). Only spans\n  whose resource carries service.layer\u003dOTLP_GENERAL are analyzed; the\n  others are stored and searchable, and the OAP logs one INFO line per\n  service whose spans carry no layer.\n- New OTLP_MESH layer, with no shipped rules, for mesh sidecars.\n- No layer: auto. A rule declares a registered layer, or the OAP does\n  not start.\n\nThe OTLP service catalog keeps the layer:\n- OTLPServiceTraffic stores service.layer in otlp_service_layer, one\n  row per name and layer, UNDEFINED when absent or unregistered.\n  IOTLPTraceQueryDAO#getServiceNames is replaced by getServices(layer),\n  filtered in BanyanDB, Elasticsearch and JDBC.\n- The stored span carries the same layer, and a TraceQL q on\n  resource.service.layer alone is answered from the catalog.\n\nNetwork aliases come from strict span pairing:\n- A caller half, keyed by its span id, meets the callee half of the\n  SERVER span whose parent is that span, on the trace\u0027s owner node.\n  prepareNetworkAlias, buildNetworkAlias and resolveNetworkAlias\n  replace the alias statement, resolveAlias and KnownServices.\n- The alias is keyed by the caller and the address it dialed,\n  frontend-\u003ecart:7070 (callerScopedAddress). The topology query folds\n  an address node by the caller-scoped row, then by the plain one.\n- pairingSamplePercent (default 25) picks the traces paired. An\n  address listed in gateways.yml is never aliased and is drawn as a\n  VIRTUAL_GATEWAY node (isGateway).\n- A SERVER span that passed its own context upstream, as nginx\u0027s\n  OpenTelemetry modules do, may send a caller half, so a proxy that\n  reports one span per request is learned on both hops.\n\nNetwork address alias writes (agent path too):\n- NetworkAddressAlias#combine skips the write of an unchanged mapping\n  written less than five minutes ago, and last_update_time_bucket is\n  the minute OAP received the setup: a stable alias costs about twelve\n  writes an hour instead of about 140.\n\nDocs: tal.md, trace-analyzer.md, otlp-trace.md, traceql-service.md,\nconfiguration-vocabulary.md, and the new\ntrace-analyzer-practices.md."
    },
    {
      "commit": "4c831c7fae2b51da926f883cb6f647f76c7259ba",
      "tree": "1a32bbc88f35a69dbbdea0eec577167df90acf65",
      "parents": [
        "cc6ed6292078b2b65cf88f90966a1d0c809ba8c5"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Oct 28 11:10:30 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 28 11:10:30 2026 +0800"
      },
      "message": "Read a tool call as its arguments in AI agent conversations (#14174)\n\nA step on one part of a record reads that part alone, as the AI\nSessionizer does since apache/skywalking-ai-sessionizer#94. The document\nread a tool call that shares a record with the agent\u0027s text as that\ntext, and a queued command kept as data beside other text as that text\ntoo. Now a tool call reads as its arguments, and a queued command as the\nprompt inside its own data.\n\nOn a local Sessionizer root, 10 of 25 LangChain tool calls shared a\nrecord with text, and 3 of 109,397 Claude Code ones. No test fixture\nholds such a record, so the documents the tests compare with the\nSessionizer\u0027s are unchanged."
    },
    {
      "commit": "cc6ed6292078b2b65cf88f90966a1d0c809ba8c5",
      "tree": "f30f42caf75e518a1f1178b4e13e229f991372c4",
      "parents": [
        "3bb97546922c2d22f29883196f1929e2e42207c2"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Tue Oct 27 17:13:45 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 27 17:13:45 2026 +0800"
      },
      "message": "Fix RabbitMQ/PostgreSQL/Zabbix meter source miswires (#14171)\n\n- RabbitMQ: `meter_rabbitmq_node_allocated_singleblock_used` / `_unused`\n  read `kind\u003dmbcs`, so the Singleblock chart repeated Multiblock. They\n  now read `kind\u003dsbcs`, and `_unused` is `carriers_size - blocks_size`,\n  as RabbitMQ\u0027s Erlang memory allocators dashboard defines it, instead\n  of the whole carriers size.\n- PostgreSQL: `meter_pg_temporary_files_rate` and\n  `meter_pg_instance_temporary_files_rate` read\n  `pg_stat_database_temp_bytes`, so \"Temporary Files / s\" charted\n  bytes per second. They now read `pg_stat_database_temp_files`.\n- Zabbix: `meter_vm_filesystem_percentage` read `vfs.fs.inode[/,pused]`,\n  i.e. inode usage. It now reads the agent\u0027s `vfs.fs.size[/,pused]`,\n  the disk space usage `df` and the Telegraf VM rule report, which\n  leaves the root-reserved space out. `vfs.fs.size[/,pused]` joins\n  the required item keys; the unused `vfs.fs.inode[/,pused]` and the\n  duplicate `vm.memory.size[pavailable]` are dropped, and\n  `meter_vm_vfs_fs_size` keeps only the used and total bytes.\n\nMetric names are unchanged, so no Horizon template or configuration\nchange is needed. Values stored before the upgrade keep the old\nnumbers, so these charts step at the upgrade."
    },
    {
      "commit": "3bb97546922c2d22f29883196f1929e2e42207c2",
      "tree": "2979bffffb15da999f20a854b821519cf716de11",
      "parents": [
        "1527483d9603eebd9f0e166053f2a824541b5b5a"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Sun Oct 25 23:27:07 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 25 23:27:07 2026 +0800"
      },
      "message": "Fix Kafka broker throughput, topic metrics and idle percentage (#14167)\n\n  The JMX exporter publishes each BrokerTopicMetrics message, byte and                                                                                                           \n  request meter twice: once per topic, and again as an all-topics total                                                                                                          \n  with no topic label. Kafka updates both on every event. The broker                                                                                                             \n  messages, bytes-in and bytes-out rules added the two together and                                                                                                              \n  reported twice the real rate; they now read only the total. The topic                                                                                                          \n  rules now leave the total out, so they no longer have an extra                                                                                                                 \n  topic\u003d\"\" series. Topic bytes-in now reads bytesin_total instead of                                                                                                             \n  bytesout_total. The network processor idle percent no longer applies                                                                                                           \n  rate() to the idle-ratio gauge. "
    },
    {
      "commit": "1527483d9603eebd9f0e166053f2a824541b5b5a",
      "tree": "446b9fa1b806beafca7930b3351ca72ae501419d",
      "parents": [
        "759c53d1287714a906ab5fbdb318e068d1c0cf69"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Fri Oct 23 22:07:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 23 22:07:56 2026 +0800"
      },
      "message": "Fix pprof task-log duration unit and Kafka broker latency metrics. (#14156)\n\nPprof task logs used SECONDS for a duration that is minutes. Kafka *TimeMs\nrules used *_count.rate (observation rate); kafka-2_0_0.yml JMX exporter has\nno *_sum, so use the exported quantile\u003d0.50 gauge instead."
    },
    {
      "commit": "759c53d1287714a906ab5fbdb318e068d1c0cf69",
      "tree": "25c29b04c816419718b5cc08298819a81772a58b",
      "parents": [
        "9a34d1186f01d922abc07cb053cf51738f1eb848"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Oct 23 17:51:59 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 23 17:51:59 2026 +0800"
      },
      "message": "Pin CI runner images to ubuntu-24.04 and macos-26 (#14166)\n\nubuntu-latest is being moved to Ubuntu 26.04 from 2026-10-19 to 2026-11-19\n(actions/runner-images#14748), so jobs land on either image during the\nrollout. macos-14 is retired on 2026-11-02 with brownouts failing jobs\nbefore that (actions/runner-images#13518)."
    },
    {
      "commit": "9a34d1186f01d922abc07cb053cf51738f1eb848",
      "tree": "002c38d02647c2ed333b2c168cf8f655febae7af",
      "parents": [
        "75192f9c280b7a6c0328310119950b2c24aba2d9"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Thu Oct 22 13:46:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 22 13:46:56 2026 +0800"
      },
      "message": "Group OTLP services from a resource attribute, and keep a service\u0027s own topology node (#14153)"
    },
    {
      "commit": "75192f9c280b7a6c0328310119950b2c24aba2d9",
      "tree": "3b945b5065c7b6ed79a17458312175cf78423164",
      "parents": [
        "8c8afdfc7dd5e9af0f6165a8fa23633c837d6563"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Wed Oct 21 14:03:30 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 21 14:03:30 2026 +0800"
      },
      "message": "Fix Kong and APISIX latency percentiles treating millisecond histogram buckets as seconds. (#14155)\n\nKong *_latency_ms and APISIX apisix_http_latency are already millisecond histograms. histogram() with no unit treated each le bucket as seconds and multiplied it by 1000, so a 100ms request was stored as 100 seconds."
    },
    {
      "commit": "8c8afdfc7dd5e9af0f6165a8fa23633c837d6563",
      "tree": "ca59e15c8ccecebe9852a774e83b4cb51e7f5de5",
      "parents": [
        "21f77989d6a9cd905763447fe2c7f67177f1848e"
      ],
      "author": {
        "name": "dennis zhuang",
        "email": "killme2008@gmail.com",
        "time": "Tue Oct 20 15:14:30 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 20 15:14:30 2026 +0800"
      },
      "message": "Fix expired records not being dropped on receipt (#14154)\n\nRecordStreamProcessor decoded a record\u0027s second-precision time bucket\n(yyyyMMddHHmmss) as a minute bucket, which put the record\u0027s time far in\nthe future, and compared the record\u0027s age in milliseconds against\nrecordDataTTL converted to microseconds, so no record was ever treated as\nexpired. Decode the bucket at second precision and convert the TTL to\nmilliseconds, as the metrics check in IMetricsDAO.isExpiredCache does.\n\nThe BanyanDB stages data generator seeds the cold node with records\nstamped 3 days in the past, so its OAP raises recordDataTTL to 5 days,\nmatching the BanyanDB TTLs it sets; the stages case keeps the default.\n\nCo-authored-by: Wu Sheng \u003cwu.sheng@foxmail.com\u003e"
    },
    {
      "commit": "21f77989d6a9cd905763447fe2c7f67177f1848e",
      "tree": "5dd5fe262b29ddaee3779f3546d8b6aebc7bde0c",
      "parents": [
        "f34b9c7ef04792fcd48869aaa44c88f2e802ebc4"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Tue Oct 20 09:16:09 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 20 09:16:09 2026 +0800"
      },
      "message": "Fix Zabbix agent sample timestamps dropping the sub-second part. (#14151)\n\n* Fix Zabbix agent sample timestamps dropping the sub-second part.\n\nAgent data items carry clock in seconds and ns within that second. The sample time used only the seconds, so meter timestamps were always whole seconds.\n\n* Reword the Zabbix sample-time changelog line and tidy its test\n\nStored metrics are minute-bucketed and never held the whole-second\ntime, so the changelog line now says where the sub-second part can\nshow: values from custom Zabbix rules using MAL rate, irate or\nincrease. Results from the bundled rules and the minute a sample lands\nin are unchanged.\n\nAlso drop the test comments that restated the assertions, and move\nsampleTimeMillis below the instance fields with the other methods."
    },
    {
      "commit": "f34b9c7ef04792fcd48869aaa44c88f2e802ebc4",
      "tree": "f42475bd335c4403262329847c76f44e02174343",
      "parents": [
        "b8d45480710379ca48397e2f27901b0584f510c0"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Oct 20 07:04:03 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 20 07:04:03 2026 +0800"
      },
      "message": "Name the store holding the span a GenAI evaluation was judged from in traceRef.type (#14152)\n\n`traceRef.type` was the span\u0027s addressing scheme, so an `OTLP` reference\ncould point into either the native OTLP store or the Zipkin store, and a\nclient could not tell which one to read the trace from. GenAITraceRefType\ngains ZIPKIN, and each listener path records the store the span went to:\nOTLP for natively stored OTLP spans, ZIPKIN for spans received by\nreceiver-zipkin or converted from OTLP with `otlpTraceStorage: zipkin`.\nThe value goes into the existing `ref_type` column. The relatedTrace\nfilters, the query validation and the evaluation span check switch on\nevery type and reject an unknown one.\n\nThe new mixed-virtual-genai e2e case judges spans from a SkyWalking\nagent, an OTLP exporter and a Zipkin exporter on one OAP, and checks that\neach record is found again through relatedTrace and names the only store\nholding its trace.\n\nThe query protocol points at apache/skywalking-query-protocol#178 and #179."
    },
    {
      "commit": "b8d45480710379ca48397e2f27901b0584f510c0",
      "tree": "a6182f0501c5800b414d7a450fc09a7b04261f86",
      "parents": [
        "d1081735d269922e9eef9872ef307c77ce9323c0"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sun Oct 18 23:09:14 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 18 23:09:14 2026 +0800"
      },
      "message": "Follow the AI Sessionizer\u0027s id and round rules in AI agent conversations (#14150)\n\nThe AI Sessionizer writes a \"%\" in a part of an id as \"%25\" and a \"/\"\nas \"%2F\" (apache/skywalking-ai-sessionizer#80). The document rebuilt the\nsession node\u0027s id with the old rule, so for a session holding either it\nfound no node, and took no time range or provider body count from it.\nIt also read sessions back out of session node ids, which could list a\nsession that does not exist and read files for it. Now it finds the\nnode by the new spelling, and lists, and reads files for, the one\nsession the rounds carry.\n\nA round holding an empty line was read past it. Session Flow says such a\nline does not decode, and the round is now refused; the newline that\nends the last line leaves nothing after it and is not an empty line."
    },
    {
      "commit": "d1081735d269922e9eef9872ef307c77ce9323c0",
      "tree": "0be518507b2ef183d9edba793fd18dac1ae41d5b",
      "parents": [
        "1e1b5681a2c1652d611eafcb98721cc40cf61ace"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sun Oct 18 16:52:54 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 18 16:52:54 2026 +0800"
      },
      "message": "Show where an AI agent conversation\u0027s model call history changed (#14149)\n\nThe AI Sessionizer now compares each model call\u0027s history with the call\nbefore it, and where the history changed it adds a history.change node\njust before the call, under the same parent, at the call\u0027s first record\n(apache/skywalking-ai-sessionizer#77). The document lists that node as a\nstep that carries no text of the record it stands on, since what it says\nis in its attributes, and orders it among the nodes at one record by the\ncall it names, and before that call, as the Sessionizer orders it.\n\nThe new history-forget fixture is the Sessionizer\u0027s scenario of that\nname, built and parsed by the Sessionizer, and the document the OAP\nbuilds from it equals the Sessionizer\u0027s, key for key."
    },
    {
      "commit": "1e1b5681a2c1652d611eafcb98721cc40cf61ace",
      "tree": "04996de55cfdf3c972846420eb9c55dee33ead85",
      "parents": [
        "f784f81944e9f9eb0c355a356a56f622573761dd"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sun Oct 18 00:24:21 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 18 00:24:21 2026 +0800"
      },
      "message": "Sync the Envoy access log proto and leave unmeasurable sidecar internal latencies out (#14148)\n\nSync envoy/data/accesslog/v3/accesslog.proto with Envoy v1.40.0 and add\nthe envoy/annotations/deprecation.proto it imports. The vendored copy\ndated from 2022 and had no upstream_request_attempt_count.\n\nThe Envoy ALS sidecar internal latencies now leave out what the access\nlog cannot measure, instead of counting it as 0:\n- the internal request latency when Envoy retried or hedged the request,\n  or the TCP proxy took more than one connect attempt\n  (upstream_request_attempt_count above 1), or nothing went upstream.\n  Envoy measures the upstream timings from the start of the downstream\n  request or connection, so the time to the first upstream byte can\n  include the earlier attempts and the delays between them.\n- the internal response latency when a timing is absent, or the response\n  details are anything but via_upstream, as for Envoy\u0027s own 504 of a\n  timeout during a retry backoff, which can carry an earlier attempt\u0027s\n  upstream timing. An upstream response that a later reset or timeout\n  ended is conservatively left out too.\nThe adapters write -1 for such a latency, and the internal latency\nmetrics in mesh.oal skip it with filter(... \u003e\u003d 0). A customized mesh.oal\nneeds the same filters, or the -1 values are averaged in.\n\nThat filter needed an OAL fix: comparing a long or double source field\nwith a number failed to compile, because the generated code passed the\nnumber as an int and Javassist does not widen it to find\nmatch(long, long). The OAL enricher now resolves the compared field\u0027s\ntype and writes the number as a literal of it, 0L or 0.0; a cast would\nnot do, as Javassist overflows the int inside (long)(3000000000).\nFilters on other fields, int ones included, generate the same code.\n\nAlso add the Envoy project\u0027s NOTICE to NOTICE and to the binary\ndistribution\u0027s NOTICE, for the Envoy proto files SkyWalking bundles."
    },
    {
      "commit": "f784f81944e9f9eb0c355a356a56f622573761dd",
      "tree": "4704738696bd6934e2d59eec056fec42e102955e",
      "parents": [
        "36803d76f09d42d311c412f62183ef4ef1bd3108"
      ],
      "author": {
        "name": "Leo Camus",
        "email": "leo.camus23@gmail.com",
        "time": "Sat Oct 17 11:29:39 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 17 17:29:39 2026 +0800"
      },
      "message": "Fix Envoy ALS sidecar internal latencies dropping whole seconds (#14147)\n\n* Fix Envoy ALS sidecar internal latencies dropping whole seconds\n\nThe internal request and response latencies were computed from\nDuration.getNanos(), which is only the sub-second part of a protobuf\nDuration. Convert the whole duration to nanoseconds instead, in both the\nHTTP and TCP adapters.\n\n* Report no Envoy ALS internal response latency when a timing is missing\n\nEnvoy leaves a timing out of the access log when it never happened, such\nas the first upstream response byte when it answers an upstream timeout\nwith its own 504, and an absent Duration reads as zero. With the whole\nDuration converted, the subtraction reported the whole wait or a negative\nvalue. Report 0 unless both timings are present."
    },
    {
      "commit": "36803d76f09d42d311c412f62183ef4ef1bd3108",
      "tree": "86c7c55bf8a690771ee62a71a6902712b6aabbbd",
      "parents": [
        "e775a04a933aab2cab0025b498a49b94c312e8f7"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Fri Oct 16 18:01:53 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 16 18:01:53 2026 +0800"
      },
      "message": "Fix eBPF access-log timestamps truncating nanosecond offsets to whole seconds. (#14145)\n\nMesh HTTP latency was quantized to 0 or 1000ms and minute buckets lost sub-second precision; convert boot Instant plus offset nanos like Envoy ALS."
    },
    {
      "commit": "e775a04a933aab2cab0025b498a49b94c312e8f7",
      "tree": "97a53556060cc1e174ea0c0343088966043fb1b4",
      "parents": [
        "8c9901c88064f5de45dae49faeb2eb4b032375a7"
      ],
      "author": {
        "name": "Leo Camus",
        "email": "leo.camus23@gmail.com",
        "time": "Fri Oct 16 02:56:36 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 16 08:56:36 2026 +0800"
      },
      "message": "Fix InstanceTraffic.combine overwriting last_ping with an older minute (#14146)"
    },
    {
      "commit": "8c9901c88064f5de45dae49faeb2eb4b032375a7",
      "tree": "f8ac1c415aca5cb2644758bcb355a6b42a33eb91",
      "parents": [
        "d13cf739968e22a6030dc8ec60e431299e45093c"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Oct 15 20:12:06 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 15 20:12:06 2026 +0800"
      },
      "message": "Build the dated Elasticsearch index names through one policy, and fix three index-list bugs (#14140)\n\nThe day step of a physical table is now decided once, from its models:\nIndexRolling (NONE, DAY_STEP, SUPER_DATASET_DAY_STEP) is recorded per\nphysical table by IndexController.LogicIndicesRegister.registerRelation,\nwhich rejects a table registered with two kinds; the catalog maps are\nconcurrent, as runtime rules register models after boot. IndexNames builds\nevery dated index name from an IndexFamily, so a caller no longer picks the\nstep. TimeSeriesUtils and TimeRangeIndexNameGenerator are removed, and\nElasticSearchClient.search takes an index array instead of a Supplier.\nApart from the fixes below, index names are unchanged.\n\nFixes:\n- Zipkin getTraces listed one daily index per day since 1970 when the query\n  started at or before the epoch. It now searches the zipkin_span family in\n  that case, as its time filter already did.\n- A model applied without a schema change skipped the isExists probe, the\n  only place its table was registered, so with logicSharding on a bundled\n  MAL rule restored after its runtime override kept the override\u0027s table.\n  StorageEsInstaller now registers in populateLocalCacheOnly.\n- OTLP queryTraceById joined the day indices into one name, so the namespace\n  went on the first only and a missing day failed the scroll. The scroller\n  now takes the indices as an array, each namespaced, skipping missing days."
    },
    {
      "commit": "d13cf739968e22a6030dc8ec60e431299e45093c",
      "tree": "3523de8477175a6531771167e42df0afb5789e64",
      "parents": [
        "cf1c2be22c6ac8c85910de5199f2ce655161c0ad"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Oct 15 14:45:02 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 15 14:45:02 2026 +0800"
      },
      "message": "Read Kubernetes metadata in the background, off the threads analyzing the data (#14135)\n\nThe lookups of pods, services, endpoints, nodes and Istio ServiceEntries\nbehind Envoy ALS k8s-mesh, the eBPF access log and MAL made synchronous\nKubernetes API calls on the gRPC handler threads, on every cache miss,\ncache expiry and failed call. A slow or unreachable API server held one\nhandler thread, with the batch it was analyzing, per access log stream,\nuntil OAP ran out of memory.\n\nThe same API calls are now made in the background, one at a time in\neach of two lanes (the first reads MAL waits for, and the rest), and\nonly for what the lookups use. Envoy ALS and the eBPF access log never\nwait: an IP seen for the first time is unknown while it is read, and is\nfound by the later lookups; an eBPF connection resolves its unknown\naddresses again on its later messages. A MAL retagByK8sMeta queues the\nreads of its pods first and waits for them up to\ncore.default.malMetadataReadTimeout (2 seconds) in all; its lookups do\nnot wait.\n\nData is read again when used core.default.k8sMetadataRefreshPeriod\n(3 minutes) after it was written, and dropped\ncore.default.k8sMetadataCacheTime (als\u003d21,mal\u003d21 minutes) after its\nlast write. Finding nothing is read again when used\ncore.default.k8sMetadataNotFoundRetryPeriod (1 minute) later, and the\nendpoints or services read are read again for a pod not in them once\nthat old, as the pod may be new. A failed read, such as for a 403 or the\nAPI server not answering, is retried when used the refresh period later\nand keeps the data read before. The reads waiting at once are of\ndistinct keys and can be limited per lane by\ncore.default.k8sMetadataReadQueueSize (als\u003d\u003csize\u003e,mal\u003d\u003csize\u003e). The reads\nare sent without the client\u0027s retries, so a failing read holds its lane\nfor one attempt, and the HTTP and TCP access log analyzers share their\nlookups.\n\nFailed and refused reads are logged as periodic summaries instead of a\nline per failure, and a resource the API server does not serve is not\nlogged. Istio ServiceEntry hostname resolutions retry with a growing\nbackoff instead of immediately, and ServiceEntries are read through the\nshared Kubernetes client."
    },
    {
      "commit": "cf1c2be22c6ac8c85910de5199f2ce655161c0ad",
      "tree": "a8c08cc93c7b347f9b88644053f7400cf7b9f66e",
      "parents": [
        "2a25e0458132aa6ba6add203d7b87b2f82540e30"
      ],
      "author": {
        "name": "Leo Camus",
        "email": "leo.camus23@gmail.com",
        "time": "Thu Oct 15 07:02:12 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 15 13:02:12 2026 +0800"
      },
      "message": "Fix ES metrics reads using superDatasetDayStep to locate indices (#14139)"
    },
    {
      "commit": "2a25e0458132aa6ba6add203d7b87b2f82540e30",
      "tree": "bf6a9b25e8ce9e7960b6be6b6226695280688686",
      "parents": [
        "1092e512e963fad27fa867a6689206cf3656c475"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Oct 15 07:48:05 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 15 07:48:05 2026 +0800"
      },
      "message": "Fix a UI template update on BanyanDB leaving a disabled template disabled (#14133)\n\nDashboardSetting.toEntity() sets disabled to false, and the ElasticSearch and\nJDBC DAOs write the whole record on an update, so an update enables the\ntemplate. The BanyanDB DAO applied a patch of only the configuration and the\nupdate time, so a disabled template stayed disabled. On ElasticSearch and JDBC\nan update is the only way to bring a disabled template back, since adding\nrefuses an existing id.\n\nchangeTemplate now writes every tag, as addTemplate does; the partial\napplyConfiguration is no longer used and is removed. The ui-management e2e\ncase updates the template after disabling it, and checks that it is enabled\nand listed again."
    },
    {
      "commit": "1092e512e963fad27fa867a6689206cf3656c475",
      "tree": "829954757a06c1c3742dca75fca9bf6112daea98",
      "parents": [
        "7f6a353a8bd3f0c55d0a9a068f1e36a33457ceb4"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Wed Oct 14 21:34:33 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 14 21:34:33 2026 +0800"
      },
      "message": "Make AI evaluation judge HTTP timeout cover response body reads (#14134)"
    },
    {
      "commit": "7f6a353a8bd3f0c55d0a9a068f1e36a33457ceb4",
      "tree": "fc4bf112108db565112512f75466040b2962cd15",
      "parents": [
        "217e2e65671adb6472702afd7baab3f87d7cf7ec"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Tue Oct 13 16:14:18 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 13 16:14:18 2026 +0800"
      },
      "message": "Add the Trace Analysis Language (TAL) to analyze OTLP traces into metrics and topology (#14129)\n\nTAL is a compiled DSL, in the new trace-analyzer module, that turns the\nspans the OpenTelemetry receiver accepts into metrics, topology and\nrecords through the meter system. It runs in both OTLP trace storage\nmodes and ahead of the receiver\u0027s head sampling.\n\nThe shipped rule, tal/otlp-default.yaml, reads the OpenTelemetry\nsemantic conventions, current spellings first and the deprecated ones as\nfallbacks. It registers OTLP services under the new OTLP_SERVICE layer\nwith otlp_service_*, otlp_service_instance_*, otlp_endpoint_* and\notlp_service_relation_* metrics, named and counted as the agent path\u0027s\ncore.oal metrics are, plus a User node for root server spans. Databases,\ncaches and brokers go under OTLP_VIRTUAL_DATABASE, OTLP_VIRTUAL_CACHE\nand OTLP_VIRTUAL_MQ with their access metrics, with\notlp_mq_destination_* per queue or topic, and slow statements are\nwritten as DatabaseSlowStatement records. A database or broker that no\naddress names is named by db.system and db.namespace, or by\nmessaging.system. A messaging receive poll is not counted as a request,\nand neither is a SERVER span whose parent ran in the same process.\n\nA peer that a client names by address is folded onto the service that\nanswered. A server span registers the address it was dialed at as a\nnetwork address alias. When no attribute carries the address, the client\nand server spans of one call are paired by trace context, across the OAP\ncluster. As on the agent path, an address listed in gateways.yml is\nnever aliased, and the rule draws it as a VIRTUAL_GATEWAY node between\nthe caller and the callee.\n\nComparisons are typed when a rule compiles, and `as T` is the only\nconversion. The statements in sink {} and persist {} vote: dropper wins\nover enforcer, and enforcer over the samplers, in any order. A record is\nwritten after the rule has run, when a sink {} ran and kept it, and\npersist {} decides whether the span itself is stored. Two rules that\ndeclare one metric with different shapes fail when they load.\n\nNew trace-analyzer settings are talFiles, dedupWindow, dedupCapacity and\npairingSamplePercent. An empty talFiles, or selector: -, stores OTLP\ntraces without analyzing them.\n\nOutside the new module, server-core gains:\n- the new layers;\n- MeterEntity relations that carry a layer per side;\n- EntityTrafficGenerator, which MAL and TAL now share;\n- the apdex and percent meter functions;\n- the TALOutputBuilder SPI;\n- an optional per-metric limit on label sets for the labeled functions,\n  which TAL sets to 50 by default;\n- case-insensitive component lookup.\ncomponent-libraries.yml also gains Connect_RPC.\n\nThe change also fixes:\n- the max and min meter functions keeping the first value of a minute\n  when two values for one entity merge, and latestLabeled dropping the\n  label sets the merged value lacks;\n- the OTLP/HTTP JSON trace endpoint reading hex trace and span ids as\n  base64;\n- the heatmap query failing on bucket bounds beyond an int;\n- LAL SlowSQL statements longer than the 2000-character column; they are\n  now cut, as the agent path cuts them.\n\nTests cover the module with unit tests, run the shipped rule over a\ntrace recorded from the OpenTelemetry Demo, and add TAL cases to the\notlp-traces native e2e on BanyanDB, Elasticsearch and MySQL."
    },
    {
      "commit": "217e2e65671adb6472702afd7baab3f87d7cf7ec",
      "tree": "16e952c232509db5bafbc1c882d1007ecc74d5e6",
      "parents": [
        "653eef50e34ba0cf1838937b71d567dc73276ea3"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Mon Oct 12 13:56:40 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 13:56:40 2026 +0800"
      },
      "message": "Adopt AI Sessionizer aa67971: a segment is an activity window (#14130)\n\nAI Sessionizer aa67971 stopped writing a segment\u0027s state and committable.\nThey could not be decided without a clock, so the last segment of every\nsession stayed open. The conversation document now lists a segment\u0027s id,\ntalks, from and to, as the Sessionizer\u0027s own document does.\n\nIts rounds also stopped repeating what they say elsewhere, such as a talk\u0027s\nloops, runs and trigger. A step\u0027s attrs carry what the round wrote, as\nbefore. A provider body\u0027s manifest no longer carries run or why; the reader\nstill accepts a manifest that does. The unused Manifest.why() and\nSessionFlowRound.Node.attrBool are removed.\n\nThe test fixtures are regenerated with that commit, and the end-to-end test\nruns it."
    },
    {
      "commit": "653eef50e34ba0cf1838937b71d567dc73276ea3",
      "tree": "00cdd527edefd7faf1e24d8cbc83392809608038",
      "parents": [
        "20e54b3816a3553e041101d1eb86bee974bea5a5"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Mon Oct 12 11:24:35 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 11:24:35 2026 +0800"
      },
      "message": "Add configurable HTTP timeout for alarm hooks (#14128)\n\n  Every HTTP-based alarm hook (Webhook, Slack, WeChat, DingTalk, Feishu,                                                                                                         \n  WeLink, PagerDuty, Discord) now bounds each HTTP request it sends by one                                                                                                       \n  deadline, alarm.default.httpTimeout (SW_ALARM_HTTP_TIMEOUT, default 12                                                                                                         \n  seconds) in application.yml, covering connecting, waiting for the                                                                                                              \n  response and reading the response body. A value \u003c\u003d 0 falls back to 12.                                                                                                         \n  The gRPC hook is unchanged.                                                                                                                                                    \n                                                                                                                                                                                 \n  The previous fixed 12-second request timeout stopped once the response                                                                                                         \n  headers arrived, so a hook endpoint that stalled while sending the body                                                                                                        \n  could hold the single alarm delivery thread indefinitely.                                                                                                                      \n                                                                                                                                                                                 \n  JdkHttpClientUtils.sendStringWithTimeout in library-util gives the                                                                                                             \n  headers and the body one shared budget, and on timeout or interruption                                                                                                         \n  cancels the body subscription, since on Java 11 cancelling the pending                                                                                                         \n  request alone leaves a stalled connection open. It requires the request                                                                                                        \n  to carry its own timeout, the only thing that aborts a request still                                                                                                           \n  waiting for the response headers.                                                                                                                                              \n                                                                                                                                                                                 \n  AlarmModuleProvider builds one HttpClient shared by every hook and passes                                                                                                      \n  it with the timeout through NotifyHandler to each hook\u0027s constructor.                                                                                                          \n  The alarm and configuration docs describe the setting.   "
    },
    {
      "commit": "20e54b3816a3553e041101d1eb86bee974bea5a5",
      "tree": "106046e9a28304e9731d87c22a17f88976760737",
      "parents": [
        "033a7ab096e2a161a854cf804ae67396a10ef40b"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Oct 09 14:28:02 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 14:28:02 2026 +0800"
      },
      "message": "Name the source of each AI agent metric (#14126)\n\nThe AI agent metrics come from two sources, and the page did not say\nplainly that each metric needs its own. The AI Sessionizer sends the\ntoken and MCP metrics. Claude Code\u0027s exporter, pointed at the OAP\ndirectly, sends cost, active time, sessions, lines of code, commits,\npull requests and edit decisions. The page said the exporter \"can also\"\nbe pointed at the OAP, which read as optional, though seven metrics stay\nempty without it.\n\nOne catalog now lists every metric with its scope, source and input\nmetric. The exporter\u0027s three resource attributes are listed with what\ngoes wrong without each, and the OpenTelemetry receiver page names the\ntwo sources and lists mcp_endpoint.yaml.\n\nThe same page named the metrics handler otlp, which matches no handler:\nenabledHandlers takes otlp-metrics. It also said the receiver reads only\nthe group, defaultMetricLevel and metricsRules nodes of a rule file,\nwhich the rule files and the code no longer follow. Both are fixed."
    },
    {
      "commit": "033a7ab096e2a161a854cf804ae67396a10ef40b",
      "tree": "96c00b8a2be3a59eb0fb837aba833cd9a5a91a31",
      "parents": [
        "49c575adecc7e5c6993c32409355851f495647c2"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Oct 08 21:57:52 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 21:57:52 2026 +0800"
      },
      "message": "Say that the Sessionizer names a LangChain JS system message too (#14125)\n\nThe AI agent conversation page said a LangChain JS serialized system\nmessage, whose role is only the class that ends its id, was masked by\nthe OAP alone, and that the Sessionizer named no record by it. Since\napache/skywalking-ai-sessionizer#56 the Sessionizer names a record that\nholds one by that class, so only a completion\u0027s prompts are the OAP\u0027s\nown. The bullet is wrapped again, since earlier edits left short and\nlong lines in it."
    },
    {
      "commit": "49c575adecc7e5c6993c32409355851f495647c2",
      "tree": "3d45bfea43f9202ae29286dd3f376cf5c477e020",
      "parents": [
        "cfd59203c90abca5c90761b5d130f30659ec2b71"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Oct 08 20:13:48 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 20:13:48 2026 +0800"
      },
      "message": "Fix what the confirming reviews of AI agent withholding found (#14124)\n\nThe reviews that confirmed the fixes of #14123 found more places where\nthe OAP\u0027s withholding did not hold, or did not agree with the\nSessionizer\u0027s own rules.\n\n- The masking walk stopped at a set of tools, so a prompt key inside one\n  kept its text. A set of tools is now masked as every value is: what it\n  is as a whole first, a system message or a list of messages with a\n  system pair, then each tool, a list inside the set as more of its\n  tools, and anything else in it like any other member. A masked tool is\n  not walked again, so a tool named like a prompt key keeps the tools\u0027\n  marker.\n- A body that is not UTF-8 text was written as a literal under its\n  stored digest and size, so the served body no longer matched its own\n  manifest. Such a body cannot be a literal byte for byte, and is now\n  withheld whole; so is a request that is not one JSON object in UTF-8\n  text.\n- A body is now held as the Session Data page says a reader holds one:\n  every field of its manifest has the type the page gives it, every\n  segment is one of its four kinds, its role is request or response, it\n  claims at most 256 MiB, every reference points at a record that\n  landed before it, a part it names is one it has, a copy has the digest\n  and length it names, and the depth is one more than its base\u0027s, or 0,\n  and at most 32. A manifest\u0027s numbers are read as integers the way the\n  rest of a file\u0027s are, with no fraction and no exponent, so 0.5, 0e0 or\n  a number past a long\u0027s range is refused rather than read as another. A\n  record landed again under an id held before it is not held, as the\n  Sessionizer\u0027s own reader holds only the first; before, a later body\n  that used a piece only the repeat held made the whole files request\n  fail.\n- Only the row the session holds is served. Any other body record,\n  request or response, is withheld whole, since what it refers to may be\n  gone from what is served. A body of another role may be a request, so\n  it is not held and none of its pieces is, and a response that used one\n  is not held either. The row held is decided as each record lands, so a\n  later file cannot change how an earlier one is served.\n- The page says that a completion\u0027s prompts and LangChain JS\u0027s message\n  id are the OAP\u0027s own rules, which the Sessionizer names no record by,\n  and states the rules a body is held by."
    },
    {
      "commit": "cfd59203c90abca5c90761b5d130f30659ec2b71",
      "tree": "d25ec450ec0146a87ded6b19984ed7b9ede8e706",
      "parents": [
        "65ca5271720dcff6a182d1b8f11866a702467a54"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Oct 08 10:45:52 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 10:45:52 2026 +0800"
      },
      "message": "Withhold the system prompt and the tool schemas as a conversation is served (#14123)\n\nAn operator who shows conversations to the people an agent served may\nneed to keep from them what the runtime sent the model, while still\nseeing it. The Sessionizer names the records that carry it, with the\nflags system_prompt and tool_schemas, and its own viewer withholds by\nthose names. The OAP stores the same files and builds the same document,\nso it now withholds the same way, at query time only: the storage holds\nevery file whole, and the ingest and the rounds do not change.\n\n- The hide setting (SW_AI_AGENT_CONVERSATION_HIDE) names what this OAP\n  withholds. It applies to every reader: the OAP knows nothing about who\n  is reading, and the routes take no parameter for it. A name nothing\n  withholds is refused at startup.\n- In the document, a step read from a named record keeps its node, its\n  flags and its size, loses its text and has state omitted. No such\n  injection names a talk or a stream, a person\u0027s input names its talk\n  whatever it carries, and no such change or execution record is\n  listed. summary.withheld counts the named records once per id. Every\n  count stays, and so do every call\u0027s provider_bodies and\n  captured_prompts, where the Sessionizer\u0027s viewer empties them: a body\n  is served masked here, not refused.\n- A file is served with what it holds of the names masked. A named\n  transcript record loses its content. A request body is rebuilt from\n  the session\u0027s bodies, as a reader rebuilds it, and masked at any\n  depth by the shapes the Sessionizer\u0027s LangChain page lists: every\n  string under a prompt key but a block\u0027s type and role, the content of\n  a system or developer message wherever it sits, LangChain\u0027s pair of a\n  role and its content, and LangChain\u0027s serialized system message,\n  whose role LangChain JS writes only in its id, become a marker; every\n  tool under a tool key keeps only its name, or the name of the one\n  object it wraps. The request is written back as a body of its own, one\n  literal segment with its own digest, so a reader that checks a body\n  against its manifest still can. The pieces that held a masked text go\n  with it, and so does a body kept whole in an unknown part, which is\n  read as the Session Data page says, as text or base64. A body that\n  refers to a rewritten one is written whole the same way, and one that\n  cannot be, or holds no id to be held under, is withheld whole, as is a\n  record with no manifest this reader knows. The file gets a closing\n  line of its own; one whose stored closing line does not check keeps\n  it, so a reader refuses the served file as it refuses the stored one;\n  one whose records stop before it ends where a reader stops, and one\n  no reader opens is served empty. The naming line says so with\n  withheld and served_digest; digest stays the stored file\u0027s. A file\n  with nothing to mask is the stored bytes, and is not read when no\n  name is written in it, with any backslash-u escape read.\n- Whether a request rebuilds within maxResponseBytes is decided from the\n  manifests before anything is built: what one rebuild holds at once,\n  about two bodies for a chain of copies. So a file is served the same\n  alone or among others. Rebuilt bodies are kept for later copies, the\n  oldest going first past the budget, as the Sessionizer\u0027s own reader\n  keeps them. A hiding read reaches no further than the head round does.\n- AI agent conversations adopt AI Sessionizer 6691c36: every document\n  carries summary.withheld, {} when nothing is withheld, and a model call\n  carries the flags of its record a reader may withhold. The fixtures\n  are built again from it, with prompt-snapshot-withheld added, and\n  input-withheld: the same scenario with the person\u0027s input named\n  system_prompt, parsed by the Sessionizer, whose whole and withheld\n  documents the OAP\u0027s equal. The banyandb e2e runs a second OAP with the\n  setting over the same storage, and checks what it serves against the\n  first.\n\nMeasured on three local Claude Code sessions of 48 to 364 files: the\ndocument builds no slower with the setting, 236 ms against 287 ms on the\nlargest, since masked steps carry no text. Serving every file of that\nsession masked took 901 ms and allocated 2.8 GB, against 671 ms and\n1.8 GB for reading them, which the view does on every open; a files\nrequest reads at most 32. The withheld documents equal the Sessionizer\u0027s\nfor the same files and names, apart from the two differences above."
    },
    {
      "commit": "65ca5271720dcff6a182d1b8f11866a702467a54",
      "tree": "98cfde2d63a8eb493a2a94d3243d9013a785e3b1",
      "parents": [
        "f115aa7c0f4ccec09c044f9cdfd2f06ec4bc284f"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Oct 07 09:41:58 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 09:41:58 2026 +0800"
      },
      "message": "Fix endpoints from logs missing from findEndpoint with a time range (#14122)\n\nfindEndpoint with a duration filters on endpoint_traffic.last_ping, which\n#12693 added and set only in EndpointTrafficDispatcher. EndpointMetaDispatcher\n(logs, virtual MQ, cross-thread parent endpoints) and HubbleEndpointDispatcher\nnever set it, so those endpoints kept last_ping at 0. EndpointTraffic.combine\ncopied the newer record\u0027s last_ping, so an EndpointMeta write also reset a\ntrace endpoint\u0027s last_ping to 0.\n\nSet last_ping in both dispatchers, and keep the larger last_ping on combine.\n\nCloses #14121."
    },
    {
      "commit": "f115aa7c0f4ccec09c044f9cdfd2f06ec4bc284f",
      "tree": "a512cbc1f9f56e38159736964a18276979d8b0df",
      "parents": [
        "52438ca9490a776a28c2d7721f07fde5f098f79c"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Sep 30 11:03:37 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 11:03:37 2026 +0800"
      },
      "message": "Fix Windows monitoring on windows_exporter 0.31.0+ and OTel Collector 0.127.0+, and CPU total counting overlapping modes (#14116)\n\nwindows_exporter 0.31.0 removed the `cs` collector and the deprecated `os`\nmemory metrics windows.yaml read, so memory total/available/used and the\ncommit metrics were empty on current exporters. Read the `memory`\ncollector\u0027s replacements instead; windows_exporter 0.29.0 or later is now\nrequired.\n\nWindows CPU modes overlap: windows_exporter\u0027s `privileged` includes\n`interrupt` and `dpc`, and the Collector\u0027s `system` includes `interrupt`.\ncpu_total_percentage summed every non-idle mode and counted that time\ntwice; it now sums user + privileged / user + system.\n\nThe OTel Collector\u0027s Prometheus receiver sends a scraped target\u0027s host only\nas `server.address` from 0.127.0, so vm.yaml and windows.yaml, which name a\nhost by node_identifier_host_name, got no host and no service. The OTel\nreceiver now falls back to `server.address` when neither `net.host.name`\nnor `host.name` is present.\n\nThe otel-hostmetrics e2e replays growing system.cpu.time counters so\nrate() runs on real increases, and both Windows e2e cases assert exact\nvalues. The win e2e also replays a recording of windows_exporter 0.31.8\nthrough OTel Collector 0.158.0, taken on a GitHub-hosted Windows runner;\nthe e2e mock sender\u0027s OTLP proto is updated to v1.11.1 so its strict JSON\nparser accepts it. The documented Collector config uses the debug exporter,\nsince the logging exporter was removed. Also correct the process-hostmetrics\ncomment on the scale of process.memory.utilization, and the Telegraf row in\nthe Linux metrics table."
    },
    {
      "commit": "52438ca9490a776a28c2d7721f07fde5f098f79c",
      "tree": "6c1ba75115069eeb35068318c6ff7a862f34f13b",
      "parents": [
        "c4ae53dab26e8e131023d9072d8cbeefd5095301"
      ],
      "author": {
        "name": "kezhenxu94",
        "email": "kezhenxu94@apache.org",
        "time": "Tue Sep 29 21:58:51 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 21:58:51 2026 +0800"
      },
      "message": "Fix Elasticsearch BulkProcessor ignoring item-level failures in HTTP 200 bulk responses (#14114)\n\nFix Elasticsearch BulkProcessor ignoring item-level failures in HTTP 200 bulk responses (#14114)\n\nElasticsearch answers `_bulk` with HTTP 200 even when it rejects individual\nitems, e.g. `cluster_block_exception` when the flood-stage disk watermark\nblocks an index, and BulkProcessor treated every such write as a success.\n\n- Decode `errors` and each item\u0027s `status`/`error` on every 200 response. A\n  rejected item fails only its own future, so a rejected metrics insert is no\n  longer cached as written and a rejected update is dropped from the cache.\n- Log one ERROR line per `_bulk` request, grouped by status code and error\n  type, e.g. `Bulk request to ES had 5000 of 5000 items rejected: code\u003d429\n  type\u003dcluster_block_exception count\u003d5000`. No document id or ES error reason\n  is logged, as the reason can embed the id. The rejected futures share one\n  exception with the same message.\n- Fail a request that has no item in the response instead of passing it.\n- When `batchOfBytes` splits a flush into several `_bulk` requests, each\n  request now completes only its own items, not the whole flush.\n- Fail the futures of a flush that errors before sending, instead of leaving\n  them pending and blocking the persistence round.\n- Point the Kong monitoring doc at the moved Prometheus plugin page. The old\n  URL, still in the frozen SWIP-8, is ignored by the dead-link checker.\n\nFixes #14113"
    },
    {
      "commit": "c4ae53dab26e8e131023d9072d8cbeefd5095301",
      "tree": "968cfc4cad97259585ebc76427771a6499f8a756",
      "parents": [
        "d9e895f560a12abaf335c51325c7d100b8359bbb"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Mon Sep 28 11:04:16 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 11:04:16 2026 +0800"
      },
      "message": "Read AI agent record times to the second, as Session Data defines them (#14112)\n\nThe conversation module read a record\u0027s time with java.time\u0027s\nISO_OFFSET_DATE_TIME, which also takes a time without seconds, such as\n2026-01-01T00:00Z. Session Data defines a time as a four-digit year, the\nletter T, the time of day to the second with a fraction of up to nine\ndigits or none, and Z or an offset such as +08:00, and a value that is not\nsuch a time means the record has no time. The AI Sessionizer reads it that\nway, so the two ordered such records differently.\n\nTimes now reads exactly that form. The documents of 94 real conversations\nare unchanged."
    },
    {
      "commit": "d9e895f560a12abaf335c51325c7d100b8359bbb",
      "tree": "aea9dc20670fe4a97bc6eb976b039641803f3d28",
      "parents": [
        "778da3d35f2e807f57853cb64065a52d97e4a473"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sun Sep 27 22:20:29 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 22:20:29 2026 +0800"
      },
      "message": "AI agent conversations: MCP endpoints, and adopt AI Sessionizer 130601c (#14108)\n\nAdd otel-rules/ai-agent/mcp_endpoint.yaml: one endpoint per MCP server and\ntool under the agent\u0027s service, `\u003cserver\u003e/\u003ctool\u003e`, with calls, calls by\noutcome and duration, from the Sessionizer\u0027s agent.mcp.calls and\nagent.mcp.duration. The token rules read agent.token.usage.\n\nThe conversation document follows AI Sessionizer 130601c, so the OAP\nanswers with the document asz conversation -json prints for the same files:\n- execution records under tool_executions, each kept once by its id, and\n  each tool step\u0027s executions; a call to an MCP server names its server\n  and tool in its attrs;\n- provider bodies taken from the join the round carries;\n- a stream\u0027s origins, the relations and a step\u0027s edges in the order they\n  happened, by position inside one stream or workflow run and by time\n  across them, never by id.\n\nThe formats are read as the Sessionizer\u0027s format pages define them, not\nas Go\u0027s libraries read them:\n- Every line is read by JsonText, a reader of JSON as RFC 8259 defines\n  it, in one loop. A line holding more than 256 objects and lists open at\n  once is refused the same way on every run. A number keeps its text.\n- A Session Data record is read by the types its page gives each field,\n  inside its parts, dropped entries and usage too. A record of another\n  shape is skipped. Integers fit in 64 bits with their sign.\n- A Session Flow frame is checked against the types of its fields. A\n  frame with a field of another type does not decode, so its round does\n  not read, and neither does one with a negative sequence, row or round.\n- Record times are RFC 3339 and compare as instants. Ties and map keys\n  sort in code point order.\n- A talk\u0027s tree is walked in one loop, siblings sort in a total order,\n  and a call\u0027s usage and a step\u0027s dropped entries are written by their\n  listed fields.\n\nThe documents of the 94 real conversations measured are unchanged by the\nreading rules. The e2e adds an mcp-calls case and pins the Sessionizer\ncommit.\n\nMALExpressionExecutionTest failed on every build from 2026-09-27. The\nEnvoy CA expiration rules subtract time() from a certificate\u0027s expiry,\nand their test data held the result recorded on 2026-03-06. The 1%\ntolerance for large values ran out about 205 days later. An expected\nvalue taken from time() is now written as value_minus_now and checked\nagainst the current second, within a minute."
    },
    {
      "commit": "778da3d35f2e807f57853cb64065a52d97e4a473",
      "tree": "275eb70efc80542c3d1619af8ba2da95690ce0c4",
      "parents": [
        "0a01d89d333ff08535b3630a38ef45fc0dcbca10"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sun Sep 27 10:34:27 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 10:34:27 2026 +0800"
      },
      "message": "Move third-party action pins to ones the ASF allow-list approves (#14109)\n\nThe ASF allow-list no longer approves docker/login-action v4.2.0,\ndocker/setup-buildx-action v4.1.0 or docker/setup-qemu-action v4.1.0, so\nevery workflow that reaches those steps fails with \"action is not\nallowed\". dorny/paths-filter v4.0.1 is approved until 2026-09-27 only.\n\nEach moves to the newest pin the list approves with no expiry date:\ndocker/login-action v4.6.0, docker/setup-buildx-action v4.4.1,\ndocker/setup-qemu-action v4.4.0 and dorny/paths-filter v4.0.3, all in\nthe same major version. Each commit SHA is the one its release tag names."
    },
    {
      "commit": "0a01d89d333ff08535b3630a38ef45fc0dcbca10",
      "tree": "8cf1033d886ff1bc16016191dbf27e6851f7c90e",
      "parents": [
        "691137d297142f1112fd7db97b5d5e14bba3ab2c"
      ],
      "author": {
        "name": "mike-realuptime",
        "email": "mike@realuptime.net",
        "time": "Thu Sep 24 00:13:17 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 24 11:13:17 2026 +0800"
      },
      "message": "Add OpenTelemetry-native host and process monitoring (#14051)\n\n  - `vm.yaml` and `windows.yaml` map both sources to the same `meter_vm_*` / `meter_win_*` metrics, one rule file per OS. Each expression adds the exporter branch to the        \n  hostmetrics branch, and a host sends only one of the two. Existing node-exporter and windows_exporter metrics keep their meaning.                                              \n  - New hostmetrics-only metrics: CPU core count and normalized CPU usage on both systems; on Windows also CPU load, file-system usage, system handle count and pagefile         \n  free/total/percentage.                                                                                                                                                         \n  - node-exporter metrics with no matching hostmetrics source (`tcp_alloc`, `sockets_used`, `udp_inuse`, `filefd_allocated`) stay node-exporter only.                            \n  - New `process-hostmetrics-linux` and `process-hostmetrics-windows` MAL rules report each process name as an instance under its host service (`mp_process_linux_*` /           \n  `mp_process_windows_*`: process count, threads, CPU, resident memory, open handles, oldest process uptime). Both are enabled by default in `enabledOtelMetricsRules`.          \n  - Reference Collector configs `docs/en/setup/backend/otel-collector-hostmetrics-{linux,windows}.yaml` group processes by normalized name before OTLP export. The Windows config\n  also renames `state` to `mode` and `process.handles` to `process.open_handles`.                                                                                                \n  - MAL test data for the new rules and the hostmetrics branches, plus a new `VM OpenTelemetry Hostmetrics` e2e case: Linux host and process metrics, raw Collector output       \n  assertions, and Windows OTLP fixtures.                                                                                                                                         \n  - UI dashboards are not included.    "
    },
    {
      "commit": "691137d297142f1112fd7db97b5d5e14bba3ab2c",
      "tree": "2e15d963cad7c300769f92e8179e616efa733f98",
      "parents": [
        "03ecf41fd7ac34635370c91e2bf01e0424fa85eb"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Wed Sep 23 14:15:48 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 23 14:15:48 2026 +0800"
      },
      "message": "Keep the TraceQL scope in the OTLP tag autocomplete (#14105)"
    },
    {
      "commit": "03ecf41fd7ac34635370c91e2bf01e0424fa85eb",
      "tree": "5996342e28b3c2110e2bb2b081f3e97d0c377029",
      "parents": [
        "ecb087cbfd23a89581367ca70adc74f511a9e70c"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Tue Sep 22 11:11:54 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 22 11:11:54 2026 +0800"
      },
      "message": "Give every span of an OTLP trace response a status (#14100)\n\nGrafana\u0027s Tempo datasource reads a span\u0027s status without checking that it is there\n(int64(span.Status.Code) in the backend\u0027s trace_transform.go), so a span served without\none crashes its trace view with a nil pointer dereference and the request fails with 500.\nThe field is optional in OTLP and senders do leave it out: APISIX\u0027s opentelemetry plugin\nsets a status only on an upstream 5xx, and until now such a span reached the OAP with the\nfield absent whenever no OpenTelemetry Collector normalized it on the way.\n\nOTLPTraceAssembler.assemble already rebuilds every span while it regroups them, so it now\nfills in an empty status when the stored span has none. An absent status and an empty one\nboth mean STATUS_CODE_UNSET, so nothing a client reads changes, and because this happens\non read the traces already stored render too. The SkyWalking and Zipkin datasources set a\nstatus on every span they convert, so only the native OTLP path needed this."
    },
    {
      "commit": "ecb087cbfd23a89581367ca70adc74f511a9e70c",
      "tree": "c0863843562e9d02222525e131c17766c91969da",
      "parents": [
        "3af86a1ec4c455e2fddb879ae51ad661112d9c78"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Mon Sep 21 16:12:05 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 21 16:12:05 2026 +0800"
      },
      "message": "Fix the OTLP TraceQL search result types and the BanyanDB name catalogs\u0027 time bound (#14099)"
    },
    {
      "commit": "3af86a1ec4c455e2fddb879ae51ad661112d9c78",
      "tree": "1ffea46bf041b3f6b437cb8b1e554540bdb403ed",
      "parents": [
        "029571c7ee78bcfcb4114255ee6da70fb2a0219a"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Sun Sep 20 20:15:49 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 20 20:15:49 2026 +0800"
      },
      "message": "Store OTLP traces natively and bring the TraceQL module closer to the Tempo API (#14096)\n\n**Native OTLP trace storage.** `receiver-otel` gains `otlpTraceStorage: otlp`, which keeps each span as the `ResourceSpans` it arrived in (`otlp_span`, BanyanDB group `otlpTrace`) with service, span-name and peer catalogs, and the TraceQL module gains an `/otlp` datasource (`enableDatasourceOTLP`) that serves those spans to Grafana Tempo without any Zipkin conversion. `otlp` is the default, so a stock `application.yml` stores OTLP traces natively and no longer needs the Zipkin modules; `otlpTraceStorage: zipkin` keeps the previous conversion to Zipkin v2 through receiver-zipkin, and that path is unchanged. `otlpTraceStorage` is validated at boot, and the Zipkin mode fails fast when `receiver-zipkin` is not enabled. Docs: `docs/en/setup/backend/otlp-trace.md`, `docs/en/api/traceql-service.md`, `docs/en/setup/backend/ui-grafana.md`.\n\n**Tempo API alignment on every datasource.** Search results list only the spans that matched in each span set (capped at `spss`) and fill `serviceStats`; `span.http.status_code` is filterable; the tag endpoints honour `scope` and the per-scope `limit`, list an `intrinsic` scope with what each datasource can filter, accept Tempo\u0027s unscoped `.key` names, and narrow tag-name and tag-value lookups by `q` from a sample of the newest 50 matching traces so Grafana\u0027s dependent dropdowns work. `/otlp` also accepts `span:name`, `span:kind`, `span:status` and `span:duration`. `/api/metrics/query_range` and `/api/metrics/query` answer `501 Not Implemented` with an error body instead of a `200` Grafana cannot parse.\n\n**Strict TraceQL (#14093).** Unsupported TraceQL is refused with `400` instead of dropping the predicate and answering with unfiltered traces: syntax errors (including `||`, which Grafana emits for multi-select), unsupported operators, negation, attribute-existence checks, multiple spansets, unknown intrinsics and values, and conditions a datasource cannot filter (`kind` on Zipkin and SkyWalking, `resource.instance` on Zipkin, `resource.remote.service` and `status \u003d unset` on SkyWalking, `resource.instance` or `name` without a service on SkyWalking). The deprecated `tags` parameter is parsed as logfmt on every datasource and goes through the same mapping and refusals. Every search-result span carries a `status` attribute next to `service.name` and `span.kind`. A trace the storage matched but none of whose spans satisfies every condition is left out instead of listed with every span; the `/otlp` matcher compares names the way the receiver indexed them, and the native tag index keeps the `resource.` and `span.` scopes apart, so `span.env` never matches a resource attribute while the unscoped `.env` matches either. `duration \u003e` and `\u003c` are strict at microsecond precision, and `/api/v2/traces/{id}?start\u0026end` bounds the lookup on every storage.\n\n**Tests.** Unit tests for the parser, the three span matchers, the assembler and converters, the handler helpers, `OTLPSpanForward` and the JDBC DAO. New e2e cases `otlp-traces/native/{banyandb,es,mysql}` and `otlp-virtual-genai/native`; `traceql/{zipkin,skywalking}` and `storage` expectations updated."
    },
    {
      "commit": "029571c7ee78bcfcb4114255ee6da70fb2a0219a",
      "tree": "1d28a5885fdc363b27301787e7b9036761f0bdda",
      "parents": [
        "289b4b3bd2e271ef6b617cfb3f64987fe29a8265"
      ],
      "author": {
        "name": "hope350",
        "email": "72125395+hope350@users.noreply.github.com",
        "time": "Thu Sep 17 11:47:27 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 11:47:27 2026 +0800"
      },
      "message": "Fix filtering events by layer on the Elasticsearch storage (#14087)"
    },
    {
      "commit": "289b4b3bd2e271ef6b617cfb3f64987fe29a8265",
      "tree": "5117f84c769a0f8369608fa6cfc2c0b0e75471db",
      "parents": [
        "d13d9e06084fd4889a7027ef0f00a8701c124220"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Sep 16 15:18:38 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 16 15:18:38 2026 +0800"
      },
      "message": "AI agent conversations: provider bodies in the view, and files over HTTP (#14084)\n\nProvider bodies in the conversation view.\nThe AI Sessionizer can land the request and response bodies an agent\nruntime exchanged with its model provider, apache/skywalking-ai-sessionizer#10.\nThey arrive as Session Data files of kind provider_body, one directory\nper session: \u003csession\u003e/provider_body/provider_body-\u003cstamp\u003e-\u003cseq\u003e.sd. The\nOAP already stored them like any other file, but gave them a wrong name,\n\u003csession\u003e/runs//..., which the raw-file query could not parse back.\n\n- FileNames names the provider_body directory and parses it back.\n- The asz.view document follows the Sessionizer\u0027s. An llm.call step lists\n  its request and then its response under provider_bodies, each as a role\n  and the ref of the landed record, never the body. summary.provider_bodies\n  and summary.captured_prompts count them. The join uses the bodies\u0027 own\n  ids: a response by its message id, a request by the previous call\u0027s\n  response request id and its prompt, and only when exactly one request\n  and one call carry them. A synthetic call takes part in no join, and no\n  request joins in a stream whose landed transcript lines have a gap.\n  Calls on one record are ordered by id, as the Sessionizer now orders\n  them.\n- What the join reads is decoded as the Sessionizer decodes it. A manifest\n  whose known keys, or its segments\u0027 keys, have the wrong JSON type is no\n  body. A record whose call or run is not a string is gone to the join. An\n  ord is read from the raw line: the digits after a leading {\"ord\":, as an\n  unsigned 64-bit number, or else the decoded value, where null is 0. A\n  transcript whose records end at a line that does not decode has a gap.\n  SessionDataFile keeps each record\u0027s leading ord digits and whether its\n  records stopped early.\n- The test data is refreshed from the Sessionizer: the two existing sets\n  gain the two summary counts, and the provider-bodies and\n  provider-bodies-errors sets are added. Both documents equal the\n  Sessionizer\u0027s key for key. A session without its provider_body file\n  folds to the same nodes, a stream with a gap joins responses only, and a\n  manifest or an ord the Sessionizer reads differently counts as it does;\n  each of those cases gave the same counts from asz conversation.\n- The e2e builds the Sessionizer\u0027s provider-bodies scenario into the same\n  root and checks the file, every call\u0027s bodies and the export by name.\n  The views, list, sender and token expectations count the new session.\n  The Sessionizer is pinned to the commit that lands provider bodies,\n  since its view now carries the two summary counts.\n\nConversation files over HTTP, not GraphQL.\nThe query protocol drops getConversationRawFiles, apache/skywalking-query-protocol#175.\nA conversation\u0027s stored Session Data files are read from a second HTTP\nroute beside the view, so a page loads what a step points at, such as an\nllm.call\u0027s provider bodies, only when a reader opens it:\n\n  GET /ai-agent/conversations/{conversation}/v1/files\n      ?service\u003d\u0026instance\u003d\u0026session\u003d\u0026seq\u003d[\u0026seq\u003d...][\u0026coldStage\u003dtrue]\n\n- A file is chosen by its session and its landed seq, the two columns the\n  storage reads it by; the Sessionizer assigns a seq once per file in a\n  session. One to 32 seqs a request: a file is cut at 2 MiB, so a response\n  holds about 64 MiB. There is no read of every file.\n- The body is application/vnd.skywalking.asz.files+ndjson: for each file a\n  naming line {file, seq, lines, bytes, digest}, exactly that many bytes,\n  and a newline after a non-empty file that does not end with one. Files\n  come in seq order, the order provider bodies are read in.\n- The read takes its time range from the newest intact round, reading the\n  rounds down from the head only until one is intact, then reads one\n  storage window of files and hands it to the response before reading the\n  next. Windows are produced one at a time and cannot overflow.\n- The route compresses with gzip itself, a chunk at a time. Armeria\u0027s\n  encoder keeps every compressed chunk of a response in one growing buffer\n  until the response ends. The view route still uses it.\n- Both routes require the service and the sender\u0027s instance, as a list row\n  names them, so every read is a full series lookup; serviceId goes. A bad\n  coldStage gets a problem document, not Armeria\u0027s plain-text 400.\n- The e2e reads files through swctl by session and seq taken from the\n  document, and passes the instance on every view and route call. The\n  raw-files case counts the three Session Data files of the first\n  conversation, since rounds are no longer served.\n\nThe e2e pins swctl to the merge commit of apache/skywalking-cli#235, which\nadds swctl ai-agent files with --session and --seqs."
    },
    {
      "commit": "d13d9e06084fd4889a7027ef0f00a8701c124220",
      "tree": "bda54748d8e2bbace8ee9cc48760eef30458c537",
      "parents": [
        "810f3c4fc86e2e7b622226900392e3efa5e8c4b0"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Mon Sep 14 22:35:30 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 22:35:30 2026 +0800"
      },
      "message": "Rename Envoy AI Gateway to Agent Router in the docs (#14082)\n\nEnvoy AI Gateway became Agent Router on 2026-09-10 and moved to the\nAgentic AI Foundation. Only the product name changed: Agent Router kept\nits API group, CLI, images and emitted telemetry. Update the operator doc,\nmenu, marketplace entry and OTLP receiver doc to the new name, and keep the\nENVOY_AI_GATEWAY layer, the job_name\u003denvoy-ai-gateway routing tag, the\nenvoy-ai-gateway rule files, the meter_envoy_ai_gw_ metric names and the\ndoc URL unchanged so existing deployments, stored data and links keep\nworking."
    },
    {
      "commit": "810f3c4fc86e2e7b622226900392e3efa5e8c4b0",
      "tree": "70b4a28786f3644ae42860a2892b8a17411b8663",
      "parents": [
        "25c74a80860dc09d6281526345650ceee46dcf37"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Mon Sep 14 15:13:40 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 15:13:40 2026 +0800"
      },
      "message": "Make AI conversation cold-stage reads opt-in (#14079)"
    },
    {
      "commit": "25c74a80860dc09d6281526345650ceee46dcf37",
      "tree": "532dddbfcd4e5ec2eccec423ad6c6b50f8383959",
      "parents": [
        "476afadecdc0a410bf5c64de48f6ead8e6030b00"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sat Sep 12 10:40:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 10:40:46 2026 +0800"
      },
      "message": "Refresh AI agent conversation fixtures for preserved source JSON (#14078)"
    },
    {
      "commit": "476afadecdc0a410bf5c64de48f6ead8e6030b00",
      "tree": "aa0c4234fb5828185119eb5853256d9ed8db63ff",
      "parents": [
        "51e727359fd00f006cf7a98511ae205176171969"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Sep 11 09:30:34 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 09:30:34 2026 +0800"
      },
      "message": "Fail fast when the e2e docker targets run on a JDK older than 17 (#14072)\n\ntest/Makefile listed docker.e2e-spring-ai-service unconditionally, but the e2e\nreactor only builds that module under its jdk-17 profile. On JDK 11 the docker\ntarget therefore copied a jar that was never produced, and on a checkout that\nhad previously built under JDK 17 it packaged a stale one instead -- `clean`\nnever reaches a module the profile excluded.\n\nNeither failure points at the cause. The missing jar is bind-mounted by path,\nso Docker creates a directory in its place and the container dies with\n\"Invalid or corrupt jarfile\", naming neither the module nor the JDK.\n\nRefuse at parse time instead, scoped to the goals that need the module so the\nother four images stay buildable by name on any JDK."
    },
    {
      "commit": "51e727359fd00f006cf7a98511ae205176171969",
      "tree": "a5e100e7effb0ee576f163fee30cd329ec0160da",
      "parents": [
        "afddbd65de6dfcb07547f4d5157bb540ae2bcc41"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Sep 11 08:11:50 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 08:11:50 2026 +0800"
      },
      "message": "Vendor the GenAI e2e Spring AI application and split out the mock LLM server (#14071)\n\nThe virtual-genai case built its Spring AI application at test time by cloning\nspring-projects/spring-ai-examples and running Maven inside the image build. That\nresolved spring-ai:2.0.0-SNAPSHOT, a line abandoned the day before the 2.0.0 GA\nwhose older builds have since been pruned, so the fixture was pinned to nothing\nreleased and could no longer be rebuilt from the same bytes.\n\nReplace it with an in-repo e2e-spring-ai-service module on the released Spring AI\n2.0.1, and move the mock LLM endpoints out of e2e-service-provider into a dedicated\ne2e-mock-llm-server that all three GenAI cases share -- e2e-service-provider was\nonly ever started in those cases to host that controller.\n\nSpring AI requires Java 17 and Spring Boot 4, while the e2e reactor targets Java 8\nand is compiled under JDK 11 on the e2e-test-java-versions leg, so the new module\nsits behind a jdk-17 profile and the jobs that build it now pin JDK 17 explicitly."
    },
    {
      "commit": "afddbd65de6dfcb07547f4d5157bb540ae2bcc41",
      "tree": "9bbea86282f9a523ae88e10089397de5cf49890a",
      "parents": [
        "adf0ecd94d966bf55e858246d05124e06fa84ac7"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Sep 10 18:43:43 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 18:43:43 2026 +0800"
      },
      "message": "Adopt AI Sessionizer workspace changes and agent runtime metrics (#14063)\n\nSession Data files of kind changes, which the Sessionizer\u0027s Claude Code\nplugin lands beside a stream\u0027s transcript with one change record per\nobserved tool call, are stored like any other file; the runtime\u0027s own\npatch for its editing tools is read from the second data part of the\ncall\u0027s result record; and the asz.view document joins every record to\nits step by tool-use id under workspace_changes, counts them in\nsummary.changes and names them on the tool step, equal key for key to\nthe document the Sessionizer builds for the same files.\n\nThe AI_AGENT layer takes the agent runtime\u0027s metrics in the new\notel-rules/ai-agent rule set: Claude Code\u0027s claude_code.token.usage, as\nits exporter sends it or as the Sessionizer derives it from the landed\ntranscripts, per service and per sender, by type, model and query\nsource with session.id summed away, plus the exporter\u0027s cost, active\ntime, sessions, lines of code, commits, pull requests and edit\ndecisions. A delta point is kept as its value at its time, and the\nOpenTelemetry receiver now analyses a request a minute at a time: a MAL\nrule folds every sample of an entity into one value at the first\nsample\u0027s time, so a request carrying a series of minutes, as the\nSessionizer\u0027s does, landed as one minute.\n\nThe e2e builds the Sessionizer\u0027s workspace-changes scenario into the\nsame root, derives the metrics with asz collect, and verifies the\nchanges files, the joined document over JSON and YAML against the\nSessionizer\u0027s viewer, and the token totals per type, model and source\nagainst what the scenarios declare. The Sessionizer is pinned to its main\nimage on which asz collect is the whole pipeline, so each stage is one\nbuild and one collect; the lost-file stage runs its two passes over a\ncopy of asz.yaml that names no receiver, deletes the file, and pushes\nonce.\n\nA round\u0027s header now counts what the conversation did as of that round,\nand Horizon\u0027s conversation list already queries them: changes with the\nlines added and removed, llm_calls, subagents and bash_runs land on\nai_agent_session_flow through the LAL rule, absent rather than zero when\nthe round did not carry them, and reach ConversationRow from BanyanDB, ES\nand JDBC; the schema is skywalking-query-protocol#173.\nThe e2e reads the list and the document the way Horizon\u0027s page does,\nevery field it asks for.\n\nThe e2e exposed two boot bugs, fixed here. The runtime-rule sync tore\ndown and reloaded every bundled MAL and LAL rule file on its first pass\nafter each boot, because StaticRuleLoader seeds a bundled rule with a\nRUNNING state while the gone-keys pass recognised a boot-seeded entry\nonly by a null state; a MAL teardown leaves the receiver without the\nfile\u0027s converter for a persistence round, so the samples of that window\nwere dropped without a log line. An entry that runs its bundled file as\nshipped is now left alone. And the core bound 11800 and 12800 in its own\nnotifyAfterCompleted, before the modules after it had booted, so a\nrequest could reach a rule set still being set up; a new\nModuleProvider.notifyBootCompleted hook runs after every module\u0027s\nnotifyAfterCompleted, and the twelve providers that bind a port for\nrequests bind there, so an accepting port means the boot is complete."
    },
    {
      "commit": "adf0ecd94d966bf55e858246d05124e06fa84ac7",
      "tree": "49e506300b4e590c9a6fd9474b08b24d6b2d76ff",
      "parents": [
        "7773bdcc7352ca98b9321f0a5849fc9cd0bc97d3"
      ],
      "author": {
        "name": "kezhenxu94",
        "email": "kezhenxu94@apache.org",
        "time": "Thu Sep 10 15:19:25 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 15:19:25 2026 +0800"
      },
      "message": "Add a none provider to the ai-agent-conversation module (#14064)\n\nThe GraphQL query module requires the module, so the \u0027-\u0027 selector cannot\nremove it. SW_AI_AGENT_CONVERSATION\u003dnone selects a provider that disables\nthe ai_agent_session_data and ai_agent_session_flow models before the core\nmodule scans them, so neither table nor the BanyanDB group they are the\nonly members of is created, answers both conversation queries empty with\nan errorReason, and registers no conversation view route."
    },
    {
      "commit": "7773bdcc7352ca98b9321f0a5849fc9cd0bc97d3",
      "tree": "04886100c2ef9655124f968d00bf73b79373e3ef",
      "parents": [
        "4fe83aaf02107d07d9b7310ff5e55864974059f5"
      ],
      "author": {
        "name": "kezhenxu94",
        "email": "kezhenxu94@apache.org",
        "time": "Wed Sep 09 13:50:02 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 13:50:02 2026 +0800"
      },
      "message": "Apply max request header size config to HTTP/2 as well (#14062)"
    },
    {
      "commit": "4fe83aaf02107d07d9b7310ff5e55864974059f5",
      "tree": "f4c5a549db8adce6ea2d2bf7c391ed45c0917ea3",
      "parents": [
        "98b9ed6baab5d2f2e390f8046e95761f3f8218f2"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Sep 09 10:59:32 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 10:59:32 2026 +0800"
      },
      "message": "Fix a persistence round ending before the storage answered (#14060)\n\nPersistenceTimer counted the delay to the next round from the moment a\nround\u0027s writes were queued, not answered: the per-worker future completed\nwhen batchDAO.flush returned, the flush\u0027s own future was used only to\nclose a latency histogram, and endOfFlush ran after that. A metric enters\nthe persistence session cache only when the storage acknowledges its\nwrite, and the BanyanDB bulk processor holds a queued write for up to\nflushInterval (15s) before sending it, so under the 25s persistentPeriod\nan acknowledgement that lagged ten seconds let the next round find the\nmetric absent from the cache, take the minute for a new one and write it\nagain with only its own points; a measure write replaces the series at\nthat time, so the earlier points were gone.\n\nA round now completes when every request of it has been answered and the\nnext round\u0027s delay counts from there, and endOfFlush, which already\nforced the Elasticsearch bulk out, now forces the BanyanDB measure bulk\nout too, so the wait is one round trip and not the bulk\u0027s interval.\n\nWaiting on the requests exposed a second gap in the BanyanDB bulk\nprocessor: when building one write failed, only that request\u0027s future\nwas failed and the unsent requests behind it were left pending forever,\nwhich would now hold a persistence round, and the runtime-rule removal\ndrain, indefinitely. Every unsent request of the aborted batch is failed\nwith the build error, requests already sent keep their completion, and\nthe error log names the entity\u0027s metadata instead of rendering the\nentity, which can invoke the serializer that just failed."
    },
    {
      "commit": "98b9ed6baab5d2f2e390f8046e95761f3f8218f2",
      "tree": "1f3fcbfba1b9fd152206f45b9f32b26d2eb6a7b7",
      "parents": [
        "ccf250ab5f8db4ea7b58d93a028f4f77c842cbbb"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Sep 09 09:31:14 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 09:31:14 2026 +0800"
      },
      "message": "Fix JDBC reads missing the second day of a range shorter than a day that crosses midnight (#14061)\n\nTableHelper walked a time range in 24-hour steps from its first instant\nto pick the day tables to read, so a range that began late on one day\nand ended early on the next never reached the second day. Every\ntime-ranged read on MySQL, PostgreSQL and H2, metrics, traces, logs,\nalarms, records and the AI agent conversation list, was missing the\nnewer day\u0027s rows for the length of the range after each midnight; the\nlast thirty minutes read at 00:10 saw only yesterday\u0027s table, and on a\nfresh install with no yesterday\u0027s table, nothing at all.\n\nThe range is now walked by calendar day from the start of its first day,\nin both the model-based and the raw-table variants."
    },
    {
      "commit": "ccf250ab5f8db4ea7b58d93a028f4f77c842cbbb",
      "tree": "87900dcd0a0bf90c59a3a660381d01388dcabc8e",
      "parents": [
        "116a0bd1e683344aee2d4c44d97a757f1bcd40e1"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Wed Sep 09 08:03:03 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 08:03:03 2026 +0800"
      },
      "message": "Support Zipkin cold-stage trace query on BanyanDB and drop the one-day default query range (#14059)\n\n`/api/v2/traces` takes an optional `coldStage` parameter; `/api/v2/trace/{traceId}` and `/api/v2/traceMany` take optional `coldStage`, `endTs` and `lookback`. They are SkyWalking additions to the Zipkin API and default to the previous behavior, so Zipkin clients such as the Lens UI keep working unchanged. The admin debugging endpoints under `/debugging/query/zipkin` accept the same parameters. The BanyanDB stages e2e now seeds two Zipkin traces three days back into the generated cold data and verifies that the hot query does not see them while the cold search, by-id and by-ids lookups do.\n\nTwo related BanyanDB changes ride along:\n\n- Queries without a time range are bound to the largest range instead of the last 24 hours, so the by-id lookups of the trace, Zipkin and TraceQL APIs cover everything the group\u0027s hot/warm stages retain. `queryTraces` without a `queryDuration` reports a 0-to-now `retrievedTimeRange`. The matching schema comments landed in apache/skywalking-query-protocol#170, and this PR bumps the submodule to that commit.\n- `BanyanDBTagAutocompleteQueryDAO` ignores `Duration.coldStage`. `TagAutocompleteData` is an index-mode measure in the stage-less `metadata` group, and BanyanDB rejects a stage on such a group with `no stage found`, so tag suggestions failed whenever the UI\u0027s cold-stage mode was on. Reproduced and verified on the stages cluster."
    },
    {
      "commit": "116a0bd1e683344aee2d4c44d97a757f1bcd40e1",
      "tree": "feabc4b3a87d9dce5be27ce69e6370e953ea8c7a",
      "parents": [
        "e27cc276a42dfb34403d2d9dcc9eedfd5e64ef55"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sun Sep 06 22:11:43 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 22:11:43 2026 +0800"
      },
      "message": "Add AI agent conversations landed by the AI Sessionizer (#14057)\n\nThe AI Sessionizer (apache/skywalking-ai-sessionizer) pushes an agent\nruntime\u0027s conversation as Session Data and Session Flow files over OTLP\nlogs under a new AI_AGENT layer. The OAP verifies each file\u0027s digest and\nline count in the bundled LAL rule\u0027s ConversationFile output builder,\nstores it verbatim in two record models, ai_agent_session_data and\nai_agent_session_flow, in a BanyanDB group of their own, recordsAIAgent,\nand answers a conversation with one asz.view 1.0 document, equal key for\nkey to the one the Sessionizer prints for the same files.\n\nThe list page and the raw-file export are GraphQL queries,\nlistConversations and getConversationRawFiles. The document itself is\nserved by GET /ai-agent/conversations/{conversation}/v1/view on the same\nHTTP server, streamed and compressed under its own timeout, because a\nlong conversation renders to tens of megabytes: measured, a 136 MB\nsession folds to a 70 MB document in about eleven seconds, past the\nserver\u0027s ten second default. Its Content-Type names the format and the\nversion, application/vnd.asz.view+json; version\u003d1.0 or the +yaml twin,\nand an error is an application/problem+json document.\n\nThe e2e builds sessions with the Sessionizer\u0027s own scenario tool, lands\none of them in three stages, pushes everything to the OAP, and compares\nevery document with the one the Sessionizer\u0027s viewer serves, over\nHTTP/1.1 and HTTP/2, as JSON and YAML, gzipped or not."
    },
    {
      "commit": "e27cc276a42dfb34403d2d9dcc9eedfd5e64ef55",
      "tree": "7227415faff993a9fea5bc36e089feba775a522d",
      "parents": [
        "7903c44dacdab1dcbf7acf9c11bea75547bca594"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Thu Sep 03 00:11:12 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 03 00:11:12 2026 +0800"
      },
      "message": "Add BanyanDB trace tail sampling monitoring (#14052)"
    },
    {
      "commit": "7903c44dacdab1dcbf7acf9c11bea75547bca594",
      "tree": "8cab6330003f729086bdf7f153d7cdb2e0882912",
      "parents": [
        "9ae0b8d3941030a192c6a194f773850de1d4cd5e"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Wed Aug 26 14:25:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 26 14:25:56 2026 +0800"
      },
      "message": "Support hot-reloading the BanyanDB credentials and TLS trust CA. (#14013)\n\n- Support hot-reloading the BanyanDB credentials and TLS trust CA.\n- Fix MultipleFilesChangeMonitor being able to silently disable every file watch in the OAP and never honouring its watching period."
    },
    {
      "commit": "9ae0b8d3941030a192c6a194f773850de1d4cd5e",
      "tree": "e99b573cc32dd6aa9be9a05b043d0df6f4c2a4f7",
      "parents": [
        "7187f57f1c31d29f7f12539ed7eabb8411568e2f"
      ],
      "author": {
        "name": "peachisai",
        "email": "2581009893@qq.com",
        "time": "Tue Aug 25 11:21:09 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 25 11:21:09 2026 +0800"
      },
      "message": " SWIP-16 Support LLM-as-Judge on Top of GenAI Observability (#13943)\n\nIntroduce an opt-in asynchronous OAP evaluation pipeline for sampled native and OTLP/Zipkin GenAI spans, with OpenAI-compatible judge configuration, typed evaluation tasks, trace-linked persistent records, GraphQL queries, score metrics, operational telemetry, documentation, and E2E coverage."
    },
    {
      "commit": "7187f57f1c31d29f7f12539ed7eabb8411568e2f",
      "tree": "6a014d5a5d7bf0b1df69196f6fe7fac2cfabf3b9",
      "parents": [
        "80c996b8bfcd999fb64c3b559b5b373c85bdaf48"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Tue Aug 25 07:04:18 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 25 07:04:18 2026 +0800"
      },
      "message": "Prepare for next release 11.1.0 (#14000)"
    },
    {
      "commit": "80c996b8bfcd999fb64c3b559b5b373c85bdaf48",
      "tree": "eec3c1fed1c45be06b3eef937da1475f623b7879",
      "parents": [
        "5839d2ad4237dca0bf2eed7d8cd3758ef7bef39a"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Mon Aug 24 20:19:54 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 24 20:19:54 2026 +0800"
      },
      "message": "Bump the default BanyanDB compatible server API version (`SW_STORAGE_BANYANDB_COMPATIBLE_SERVER_API_VERSIONS`) from `0.10` to `0.11`. (#13997)"
    },
    {
      "commit": "5839d2ad4237dca0bf2eed7d8cd3758ef7bef39a",
      "tree": "8496d10d14dc5823277d39d0fc19550e43c74f25",
      "parents": [
        "521b2ab5d665d91fb9771258cbb95db33aa6cd16"
      ],
      "author": {
        "name": "Wilson",
        "email": "13622993145@163.com",
        "time": "Thu Aug 20 23:04:47 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Aug 20 23:04:47 2026 +0800"
      },
      "message": "Add Spring LDAP component definitions (#13984)\n\nRegister spring-ldap as component 179 and LDAP as component 180.\nMap the Spring LDAP client component to the LDAP server component and\ncover the catalog definitions with tests."
    },
    {
      "commit": "521b2ab5d665d91fb9771258cbb95db33aa6cd16",
      "tree": "393b2c72a34c1c0df6a39caca9331fc69bd0ed1c",
      "parents": [
        "102af09b4a56064e22050dded10e2c52e490d040"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sat Aug 15 08:57:27 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 15 08:57:27 2026 +0800"
      },
      "message": "Add ThreadPolicy.ioBound for blocking consumers, fix BatchQueue shutdown (#13979)\n\n`ioBound(N)` declares that a queue\u0027s consumers spend most of their time\nblocked, typically on I/O. Such a queue runs its drain loops on virtual\nthreads where the runtime provides them (JDK 25+, via\nVirtualThreads.createScheduledExecutor) and on N platform threads\notherwise. The count is identical on both paths, so concurrency,\nbatching, back-pressure, drop semantics and per-partition ordering are\nunaffected by the fallback — only the thread substrate changes, plus\nshutdown latency, since the platform scheduler can drop drain tasks\nparked on their idle backoff and the virtual adapter cannot.\n\nThe purpose is narrow: avoid paying for N parked OS threads. It does not\nraise concurrency, because the drain loop is the task processor and\nnothing is handed off — consumer concurrency is\nmin(threadCount, partitionCount) either way, so an IO-bound queue wants\nthreads and partitions 1:1 with a small per-partition buffer. There is\ndeliberately no CPU-proportional form and no cpuCores(...).ioBound():\nvirtual threads are not preemptive, so CPU-bound work would hold its\ncarrier and starve the pool shared with GRPCServer and HTTPServer.\nL1/L2/TopN stay on cpuCores/fixed. No shipped queue uses the new policy.\n\nshutdown() separately had a pre-existing race: it ran the final drain on\nthe caller\u0027s thread while drain loops could still be running, invoking a\nhandler from two threads and breaking the single-drain-thread invariant\nworkers such as MetricsAggregateWorker document. It now cancels the\nperiodic rebalance task — which does not read `running`, and whose loop\non a virtual-thread scheduler exits only on interrupt — shuts the\nscheduler down, waits for orderly exit, and takes an exclusive dispatch\nlock before draining.\n\nThat lock, not the wait, is the guarantee: awaitTermination is a courtesy\nthat may time out or be interrupted. Drain loops hold the read lock for\nthe whole cycle — the running recheck, the dequeue, notifyIdle() and the\ndispatch. All four are needed: an unlocked dequeue lets shutdown dispatch\na newer batch ahead of one a task already holds, so the older batch lands\nafter shutdown() returned; notifyIdle() outside the lock runs onIdle()\nconcurrently with the final dispatch, and MetricsAggregateWorker flushes\nthe same worker state from onIdle(); and the loop\u0027s running test can pass\njust as shutdown completes. Read locks are shared, so drain loops still\ndispatch concurrently with one another. A consumer is never interrupted\nmid-batch, so no truncated executeBatch or stream send.\n\nCallers that lose the shutdown CAS await the winner\u0027s completion latch,\nunbounded — the winner may spend all of shutdownTimeoutMs in\nawaitTermination and then block on the write lock for as long as a\nconsumer runs, so any fixed bound would let a loser return while the\nqueue is still draining. The platform scheduler also sets\nsetExecuteExistingDelayedTasksAfterShutdownPolicy(false) so drain tasks\non their idle backoff do not hold up termination; interrupts are deferred\nand restored only after dispatch returns.\n\nAlso fixes a long-standing test bug that has kept master\u0027s CI red. Four\noal-rt tests register scopes in @BeforeAll with a single try around the\nwhole block. notify() throws when a scope id is already registered, so\nonce any sibling has registered even one scope, the first call throws and\nevery scope after it is silently skipped — the tests then fail at use\ntime with \"ScopeDefine name \u003d ... not found\". OALSourceAttributionTest\nregisters Service alone, so whenever surefire\u0027s file-system order puts it\nfirst, OALClassGeneratorV2Test loses Endpoint, ServiceRelation,\nK8SServiceInstance and TCPService. That order occurs on the CI runners\nbut not on macOS, which is why it reproduces only in CI. Reproduced\nlocally with -Dsurefire.runOrder\u003dreversealphabetical, and each\nregistration is now guarded independently. The module passes under\nfilesystem, alphabetical and reversealphabetical ordering."
    },
    {
      "commit": "102af09b4a56064e22050dded10e2c52e490d040",
      "tree": "0fd5efe357307756f453310c32b7422fc31a371a",
      "parents": [
        "679b5c6e189e7a122a53238011d92e83f8954cf2"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Aug 11 19:00:30 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 12 10:00:30 2026 +0800"
      },
      "message": "Point the APISIX guide at the deployed rules file and document the service.name trap (#13978)\n\nThe customization step pointed at the source tree. Operators edit the deployed\ncopy, /config/otel-rules/apisix.yaml (apm-dist packages otel-rules/** into\nconfig/), and every other monitoring guide that names its rules file uses that\npath. Name it first and keep the source link alongside.\n\nAlso record why skywalking_service exists. The Collector\u0027s Prometheus receiver\nconverts the Prometheus job label into the service.name resource attribute, and\nOpenTelemetryMetricRequestProcessor maps service.name back to job_name - the\nlabel the APISIX MAL rule filters on. Setting service.name to name the service\ntherefore changes the filter key, the rule stops matching, and no APISIX metrics\nare produced. Reaching for the OTel-idiomatic attribute is the obvious move and\nit fails silently, with nothing in the docs to explain it.\n\nAdds one line noting each metric name is metricPrefix + the rule entry\u0027s name,\nso a reader who opens apisix.yaml can connect sv_http_requests to\nmeter_apisix_sv_http_requests."
    },
    {
      "commit": "679b5c6e189e7a122a53238011d92e83f8954cf2",
      "tree": "5f5837937bb442678e6817a55bf35df684ae948e",
      "parents": [
        "dae21cec50199cd656516f318f9d6b6c30878f30"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Aug 11 18:20:49 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 12 09:20:49 2026 +0800"
      },
      "message": "Drop runtime-rule\u0027s retired-IT dependencies and declare server-testing at test scope (#13977)\n\nruntime-rule\n------------\nSix test-scoped dependencies staged the plugin-side ITs (MalApplyRollbackIT,\nMalShapeBreakIT, StorageStackHarness, TwoNodeClusterHarness and friends) that\nwere retired in favour of e2e. The ITs never reached master; the dependencies and\ntheir explanatory comments did, so the POM documented collaborators that do not\nexist - a reader following the comments to StorageStackHarness finds nothing.\n\nThat coverage is not lost. It lives in test/e2e-v2/cases/runtime-rule/ - MAL over\nBanyanDB / PostgreSQL / Elasticsearch, LAL, meter, and the two-node cluster case -\nsix jobs wired into skywalking.yaml. The changelog says so, so the next reader\ndoes not have to reconstruct it from an unmerged branch.\n\nserver-testing scope\n--------------------\nserver-testing ships test scaffolding (ModuleManagerTesting, MockModuleManager,\nthe MAL/LAL/Hierarchy rule loaders) plus two empty org.junit stubs that let\nTestcontainers\u0027 GenericContainer hierarchy resolve without JUnit 4. Four modules\ndeclared it at compile scope - including the server-configuration parent, so all\neight configuration-* children inherited it - which put those org.junit stubs on\nthe runtime classpath that server-starter\u0027s copy-dependencies (includeScope\nruntime) packages into oap-libs. Shipping empty org.junit types is a hazard for\nanything that later puts real JUnit on an OAP classpath.\n\nModules whose tests need the stubs now declare the dependency themselves instead\nof inheriting it transitively: meter-analyzer, library-client,\nstorage-elasticsearch-plugin and storage-jdbc-hikaricp-plugin. Source greps\ncannot find these - a test that builds a Testcontainers GenericContainer forces\njavac to resolve TestRule through its superclass chain with no import to match -\nso the set was derived from which modules\u0027 tests touch org.testcontainers, and\nconfirmed by a full build.\n\nlibrary-banyandb-client also gains the direct library-util dependency its\nBanyanDBClient always needed: it was resolving StringUtil through\nserver-testing -\u003e library-module -\u003e library-util, i.e. production code reaching a\nutility class through a test-support module. Its library-integration-test\ndependency moves to test scope as well (zero src/main references, two in\nsrc/test; the only compile-scope declaration of that artifact in the repo).\n\nNo production code, no test code, no behaviour change."
    },
    {
      "commit": "dae21cec50199cd656516f318f9d6b6c30878f30",
      "tree": "a923f2d85a04dc58d3fe7e8fa68a376cb332e4df",
      "parents": [
        "092dd69f33b95e44a6d974f6e5a35a937c31d06d"
      ],
      "author": {
        "name": "Yilia Lin",
        "email": "Yilialin@apache.org",
        "time": "Tue Aug 11 16:11:38 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 11 16:11:38 2026 +0800"
      },
      "message": "Fix APISIX monitoring guide configuration and metrics (#13976)"
    },
    {
      "commit": "092dd69f33b95e44a6d974f6e5a35a937c31d06d",
      "tree": "a7d459a52fcb309e3e5b446b8e98772a49ffc35b",
      "parents": [
        "75a07d88ba91bc6fc60411d3334b09e673e19a49"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Aug 11 00:29:01 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 11 15:29:01 2026 +0800"
      },
      "message": "Use imports instead of inline fully-qualified names in the DSL compilers (#13975)\n\nCLAUDE.md bans fully-qualified class names written inline where an import would\ndo, and names the exact form Analyzer.java:242 used: a field declared as\n`private javassist.ClassPool pool;`. 44 such sites across 14 files in the four\nDSL modules -- parameter and field types, locals, throws clauses, static calls, a\nclass literal and a method reference.\n\nEvery one is a name the COMPILER resolves. Nothing resolved at runtime was\ntouched: no FQCN inside a codegen string literal, none in a FreeMarker template,\nnone handed to Class.forName or to Javassist. That distinction is the whole risk\nhere -- Javassist\u0027s compiler has no import statement and resolves simple names\nonly against java.lang, so shortening a name in generated source compiles as Java\nand then fails when the rule is compiled.\n\nThe transform only rewrote lines containing no quote character, which is sufficient\nrather than merely convenient: a Java string literal cannot span lines under JDK\n11, so a line with no quote cannot be inside one. Simple-name collisions and\nin-file shadowing were checked before any import was added; there were none.\n\nAdds a short CLAUDE.md to code-templates-v2/ saying the templates must stay fully\nqualified. Those files are the weakest spot, because they are not Java and a\nreader editing one has no reason to consult a Java style rule."
    },
    {
      "commit": "75a07d88ba91bc6fc60411d3334b09e673e19a49",
      "tree": "307ab1606e91a68ad0a817d24ca0645dd7d43b7b",
      "parents": [
        "f5a5063586383ec0cea91f2607b017e7ae61c5a0"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Mon Aug 10 22:07:42 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 10 22:07:42 2026 -0700"
      },
      "message": "Move DSL class loading under core/dsl, de-duplicate class definition, and name the classify branches (#13974)\n\nThree pieces of DSL-internals cleanup. No behaviour change.\n\ncore/classloader held only DSL types, two of which say so in their names, and\nnothing outside the DSL and rule world imported it. It is now\ncore/dsl/classloader. Catalog moves to core/dsl instead: a rule-file taxonomy is\nnot a class-loading concern, and it is the package\u0027s most-used type, mostly as a\nRuleKey component in dsl-debugging. Nothing names this package in a string\nliteral, a FreeMarker template or an SPI file, so the compiler catches every\nreference; ClassLoaderGc builds its unload-probe resource path from\nUnloadProbePayload.class.getName() rather than a constant, so it follows the move.\n\nThree copies of \"define this generated class into the right loader\" -- MAL\u0027s and\nLAL\u0027s generators and MeterSystem -- collapse into a static\nBytecodeClassDefiner.define. It lives on the interface rather than in a class of\nits own because the whole decision is whether the loader implements that\ninterface; a second similarly-named type in the same package would be one concept\nwith two names. The JDK 17 --add-opens rationale, previously restated in four\nplaces, now has one home and the other three point at it. MeterSystem\u0027s\nmulti-catch drops | IOException, which define() wraps into CannotCompileException\n-- already an arm of the same catch, so the rollback and UnexpectedException wrap\nare unchanged. That arm was unreachable regardless: CtClass.toBytecode() writes to\na ByteArrayOutputStream whose close() is a documented no-op, so the checked\nexception is a declaration artefact.\n\nThree of the four copies of the SW_DYNAMIC_CLASS_ENGINE_DEBUG dump-directory\nlookup become DslGeneratedFileWriter.resolveClassDumpDir. OAL keeps its own: its\nopenEngineDebug flag is settable independently of the environment variable and two\ntests call setOpenEngineDebug(true), which the shared resolver cannot express\nwithout a second variant invented for one caller.\n\n/addOrUpdate chose its delta classifier with a MAL/LAL ternary, written when those\nwere the only two engines, so its else meant LAL and would hand a third engine\u0027s\nrule to the LAL classifier. The decision is now three-valued and named\n(engineKindFor). An unknown catalog cannot reach it -- validate() rejects that\nearlier with invalid_catalog, using the same registry lookup -- so the third case\nmeans a registered engine with no delta classifier, which should fail loudly\nrather than parse as LAL. DSLScriptKey.isMalCatalog and isLalCatalog go with it:\none caller between them. RuntimeRuleServiceEngineKindTest covers the dispatch,\nwhich had no test because it lived inside a private handler needing a DSLManager,\nstorage and locks.\n\nDslSourceRef records a decision not to add a shared producer interface for rule\ncoordinates. Two of the four DSLs could not implement one -- OAL\u0027s dispatcher\ndeliberately wants a lineless ref, and Hierarchy has no per-rule object -- so the\nnarrow entrance, a file and a line, stays the contract and each DSL keeps what it\nknows about its own rules."
    },
    {
      "commit": "f5a5063586383ec0cea91f2607b017e7ae61c5a0",
      "tree": "d2d5ba49bba64c0443326c759ed2457587a6589b",
      "parents": [
        "a2f1f16c570140c9333ebbe06a50cec3725283dc"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Mon Aug 10 18:55:19 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 11 09:55:19 2026 +0800"
      },
      "message": "Fix LAL segmentId/spanId extractor statements; delete dead DSL code and correct the kernel\u0027s docs (#13973)\n\n```\nFollow-up to #13972, carrying one bug fix found while writing missing coverage, plus the\ndead-code and documentation cleanup that led to it.\n\nLAL segmentId and spanId extractor statements never worked\n----------------------------------------------------------\nLALParser.g4 declares traceIdStatement, segmentIdStatement and spanIdStatement as extractor\nalternatives; LALScriptModel.FieldType has all three; LALBlockCodegen\u0027s output-setter table\nalready carried setSegmentId and setSpanId, and LogBuilder implements both. Only\nLALScriptParser.visitExtractorStatement was missing two branches, and its if-chain ended with\nan unchecked assumption:\n\n    return (ExtractorStatement) visitIfStatement(ctx.ifStatement());\n\nso a rule containing \"segmentId parsed.seg as String\" failed at boot with\n\n    NullPointerException: Cannot invoke \"LALParser$IfStatementContext.condition()\"\n    because \"ctx\" is null\n\nnaming a construct the rule does not contain. That fall-through is why two of the three\nstatements stayed unimplemented: the failure never pointed at them. Both branches are added,\nand an extractor statement matching no branch now reports its own rule line.\n\nNo existing behaviour changes. LogBuilder.init copies trace id, segment id and span id from\nthe log\u0027s metadata and skips that copy only when a rule already set them; no shipped rule\ndoes, which is why nothing surfaced the gap.\n\nDead code\n---------\nEach verified against Java, resources, SPI files, codegen string literals and FreeMarker\ntemplates - the last two matter, since a class named only from a .ftl looks dead to every\ntool (OALDebug is exactly that, and is untouched).\n\n  - DslContentHash, a byte-identical zero-caller twin of the live ContentHash, whose javadoc\n    instructed the reader to consolidate toward the dead copy\n  - oal-rt\u0027s metrics-function registry (3 classes), a second divergent answer to what\n    MetricsHolder already does\n  - LogAnalyzerFactory, sole occupant of its package\n  - LALCodegenHelper.METADATA_GETTER_ALIASES, an empty map whose reader branch could never\n    execute; the DSL-name-to-getter mismatch it existed for no longer exists, because\n    LogMetadata.TraceContext names the field traceSegmentId directly\n  - MALCodegenHelper.RUN_VAR, MALExprCodegen.getVarCount, DslYamlLineIndex.empty\n\nThe kernel was asserting consumers it does not have\n---------------------------------------------------\nThree server-core classes justified their placement by naming users that grep disproves.\nDSLClassLoaderManager claimed the meter and log compile paths reach for its singleton;\nneither analyzer references it. LogDataDebugDump claimed core LALOutputBuilder\nimplementations render through it; zero core references, one caller in log-analyzer.\nDslContentHash pointed at a consolidation that never happened. A false rationale in a shared\nkernel is a standing instruction to put more things there, so each now states what the call\nsites support.\n\nThe converse was missing too: OALDebug, OALDebugRecorder and DebugHolderProvider are\nOAL-specific and by symmetry belong in oal-rt, but cannot move, because dsl-debugging\ndeclares no oal-rt dependency and its recorder implementation would lose sight of them.\nNothing said so. Now recorded on all three.\n\nResidue from #13972\n-------------------\nFourteen comment sites. The worst contradicted the code beside it: LALClassGenerator stated\nthat no LineNumberTable is attached, eleven lines above the call that attaches one and above\na test from the same PR asserting every method carries one. Also a javadoc block orphaned\nwhen a method was inserted between it and its owner, a {@link} to a method that PR deleted,\nescapeJava / sanitizeName / COMPANION_SAM_LINE_IN_CLASS named after removal, a\nlog.debug(\"MAL YAML line index ...\") in a class now serving four DSLs, and a hierarchy\njavadoc example missing the line number the code emits.\n\nTwo small corrections\n---------------------\nMALClassGenerator now uses MALCodegenHelper.GATE_HOLDER_FQCN instead of shadowing it with an\nidentical local literal - the constant read as dead only because of the shadow, while LAL\nuses its equivalent at six sites. setYamlSource gains the @Deprecated its LAL and Hierarchy\ncounterparts already carry.\n\nCLAUDE.md: why generated source is fully qualified\n--------------------------------------------------\nJavassist\u0027s compiler has no import statement. It resolves simple names only against\nClassPool.importedPackages, initialised to java.lang and nothing else; widening it needs\nClassPool.importPackage, which is pool-wide mutable state and is never called here. So\ngenerated source must fully qualify everything, java.util.Map included, and the project\u0027s\nno-inline-fully-qualified-names rule applies to hand-written Java only. Shortening an FQCN\ninside a codegen string or a .ftl compiles as Java and then fails at runtime.\n\nTests\n-----\nDedicated LAL coverage, none of which existed - METADATA_TRACE_GETTERS had no rule and no\ntest exercising any entry, in either direction, and the harness could not express it: the\nfixture builder understood only trace-id, and the execution test had no expectation for\nthese fields. Both are extended, then used:\n\n  - trace-context-read     reads all three via log.traceContext.*\n  - trace-write-all-three  writes all three from an extractor, overriding metadata\n  - trace-segment-override segmentId alone, the exact shape that threw\n\ntrace-segment-override failed with the NPE before the parser fix and passes after."
    },
    {
      "commit": "a2f1f16c570140c9333ebbe06a50cec3725283dc",
      "tree": "65ae5ef09c021405ec0125aa7777342f9fd40597",
      "parents": [
        "ec1f9a3c98ddf7bcfc82e50d4580a10228ea0703"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Mon Aug 10 07:12:16 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 10 22:12:16 2026 +0800"
      },
      "message": "Unify DSL source attribution across OAL, MAL, LAL and Hierarchy (#13972)\n\n\nOAP compiles four DSLs to bytecode at runtime — OAL, MAL, LAL and Hierarchy. Each one\nindependently grew its own answer to the same question: *when a generated class shows up in a\nstack frame, what does it say it came from?* The workflows are near-identical (rule file + line →\ngenerated class name, `SourceFile`, `LineNumberTable`, optional `.java` dump), but because each\ncompiler implemented it separately, they drifted — differently, and silently.\n\nThis PR extracts that one workflow into `org.apache.skywalking.oap.server.core.dsl` and makes all\nfour use it.\n\n#### What a frame said before, and says now\n\nThe `.java` sidecar is written **only** under `SW_DYNAMIC_CLASS_ENGINE_DEBUG`; Javassist compiles\nfrom an in-memory string, so in a released image there is no `.java` on disk — in the container,\nin a binary package, or in an IDE. A `SourceFile` naming only the generated class therefore\naddressed nothing an operator could open.\n\n| | before | after |\n|---|---|---|\n| MAL rule | `vm_L25_cpu_total.java` | `(otel-rules/vm.yaml:25)vm_L25_cpu_total.java` |\n| LAL rule | `default_L3_default.java` | `(lal/default.yaml:3)default_L3_default.java` |\n| Hierarchy rule | `hierarchy_definition_Lunknown_name.java` | `(hierarchy-definition.yml:2)hierarchy_definition_L2_name.java` |\n| OAL metric | `ServiceRespTimeMetrics.java` | `(core.oal:20)ServiceRespTimeMetrics.java` |\n| Zabbix rule | *(no coordinate at all)* | `(zabbix-rules/agent.yaml:20)agent_L20_cpu.java` |\n\nThe rule leads, then the generated file name, so the coordinate survives whether or not the\nsidecar exists.\n\n#### The shared kernel\n\nNew, in `server-core`:\n\n- **`DslSourceRef`** — the value object for one coordinate. The **only** parser of `\"file:line\"`,\n  the only renderer of `(file:line)Class.java`, and the only builder of the `_L\u003cline\u003e_` class-name\n  segment. Promoted from MAL\u0027s `MalSourceRef`, which had been written but never instantiated.\n- **`DslGeneratedFileWriter`** — all bytecode/disk side effects: `writeClassFile`,\n  `writeSourceFile`, `setSourceFile`, `attachSignatureLine`, `addLocalVariableTable`,\n  `lineOfMethod`. Split out of `DslSourceRef` so the value object performs no I/O.\n- **`DslClassNaming`** — `stem` / `allocate`. The stem is shared and deterministic; the\n  *allocation* policy stays with each generator, because it genuinely differs (MAL and LAL give\n  each runtime-rule apply its own classloader and must not dedup process-wide; Hierarchy defines\n  into the shared loader and must).\n- **`DslJavaSourceText`** — `toIdentifier` / `toLiteral`: making arbitrary rule text safe to embed\n  in generated Java source, in identifier position and in string-literal position.\n- **`DslYamlLineIndex`** — moved up from `meter-analyzer` (was `MalYamlLineIndex`), now serving\n  MAL, LAL and Zabbix by rule ordinal, plus a new `keyLines` for Hierarchy, whose rules are a YAML\n  **mapping** rather than a sequence and so cannot be matched positionally.\n\nWhat actually collapsed (counted against `master`):\n\n| duplicated logic | before | after |\n|---|---|---|\n| `\"file:line\"` parsers | 3 | 1 |\n| `SourceFile` string built + attribute written | 4 | 1 |\n| `_L\u003cline\u003e_` class-name builders | 3 | 1 |\n| identifier sanitisers | 3 | 1 |\n| Java-literal escapers | 4 | 1 |\n| process-wide dedup sets | 3 | 1 |\n| `.java` source-file writers | 3 | 1 |\n| `.class` file writers | 4 | 1 |\n| `LocalVariableTable` writers | 3 | 1 |\n| fixed line-offset constants | 1 | 0 |\n\nThe remaining per-generator wrappers that only forwarded to the shared class were removed too, so\neach generator now calls it directly — a wrapper that adds a hop without value would have made the\nconsolidation nominal rather than real. Three more copies went the same way:\n\n- **`escapeJava`** was quadruplicated, char-identical in MAL, LAL and Hierarchy, with a\n  null-tolerant fourth in OAL behind a \"kept local so this generator stays self-contained\" comment\n  that its own imports had already falsified. Deliberately *not* replaced by `commons-text`\n  `StringEscapeUtils.escapeJava`: that also escapes non-ASCII to a `u`-prefixed hex escape, and\n  Javassist has no unicode-escape pre-lex phase the way javac does, so a rule with a non-ASCII tag\n  key would compile with the escape taken literally.\n- **`sanitizeName`** left residue after the migration — LAL\u0027s copy was dead, MAL\u0027s had one live\n  caller, and that caller names a generated *variable*, not a class.\n- Both therefore landed in a new `DslJavaSourceText` (`toIdentifier` / `toLiteral`) rather than in\n  `DslClassNaming`: they are one concern — embedding arbitrary rule text in generated Java source —\n  with two positions, and neither is class naming. `DslClassNaming` keeps `stem` and `allocate`.\n- The two remaining `*.v2.dsldebug` packages became `*.v2.dsl.debug`, matching\n  `core.dsl.debug`. They stay in their modules: the dependency direction is one-way, so moving them\n  into `server-core` would create a cycle. Two of the references are string literals in codegen,\n  which no compiler would have caught.\n- **`readAll`** in `HierarchyDefinitionService` hand-rolled a buffer loop while every other rule\n  loader in this PR reads `new String(bytes, UTF_8)`. Now the same idiom.\n\n#### Loader fixes — the coordinates had to exist before they could be unified\n\nThree loaders never stamped what the generators were about to read:\n\n- **MAL** (`Rules.parseRule`) — nested rules lost their ruleset directory, and a `.yml` file was\n  reported as `.yaml`. Now stamps `rulesetDir + \"/\" + relPath` with the real extension. `Rule`\n  needed an explicit `getSourcePath()` because Lombok `@Data` was generating a getter that\n  **shadowed** the interface default.\n- **LAL** (`LALConfigs`) — resolved no line at all; now indexes the `rules:` sequence and stamps a\n  catalog-qualified `lal/\u003cfile\u003e`. The runtime-rule applier (`LalFileApplier`) stamps `lineNo` too,\n  so a hot-updated rule is attributed the same as a bundled one.\n- **Zabbix** (`ZabbixConfigs`) — `ZabbixConfig` implements `MetricRuleConfig` but took every\n  default, so `getSourceName()` was null and its classes carried neither file nor line. Now stamps\n  both, indexing under zabbix\u0027s own `metrics:` key.\n\n**Identity and attribution are separate fields.** `sourcePath` is the catalog-qualified path a\ngenerated class names; `sourceName` is the rule file\u0027s identity, and on the boot route it becomes\nthe middle component of the dsl-debugging `RuleKey (LAL, sourceName, ruleName)`. An earlier\nrevision of this PR overloaded one field for both, catalog-qualifying `sourceName` for attribution\nand thereby re-keying every static binding. They are now split, both derived through one\n`LALConfigs.stampSource`, and `MetricConvert` guards on the field it actually passes rather than\nits sibling.\n\n#### Bug fix: a hot-updated LAL rule stranded its own debug binding\n\nSeparately from the fields above, the dsl-debugging `RuleKey (catalog, name, ruleName)` names a\nrule FILE in its middle component — and the two routes that publish it disagreed on the extension.\nThe boot loader published `(LAL, \"default.yaml\", rule)`; the runtime-rule engine\n(`LalRuleEngine.publishDebugBindings`, which never reads `sourceName` — it builds its own key from\nthe rule\u0027s bare name) published `(LAL, \"default\", rule)`. Both land in the same\n`LALHolderRegistry` map, so the two keys simply never met: a hot update added a second binding\ninstead of replacing the first, `unpublishDebugBindings` could never remove the first either, and\nan operator addressing the older spelling enabled probes on a `GateHolder` belonging to a compiled\nrule that no longer evaluates anything — indistinguishable from a rule with no traffic. No\nexception, no log line.\n\n`RuleKey` now drops a trailing `.yaml`/`.yml` from that component, in its constructor rather than\nat each publish site: normalising per-site leaves the next site free to get it wrong, and doing it\nin the key also lets the REST API keep accepting both spellings, so no existing operator script\nbreaks. Only a YAML extension is stripped — OAL files stay `core.oal`, nested MAL bundles stay\n`activemq/activemq-broker`, and `vm.linux.yaml` keeps its `vm.linux`.\n\n**Rule execution was never affected.** The maps that decide which rules run are keyed by layer and\nrule name (`LogFilterListener.Factory.dsls`) and contain no file name at all; this was confined to\nthe debugging registry. The mismatch predates this PR — MAL was never affected, because both its\nroutes already publish the bare name.\n\n#### Per-method line numbers\n\n`LineNumberTable` entries now point at a method\u0027s own signature line in the generated source\n(`attachSignatureLine` + `lineOfMethod`), for OAL metrics/dispatcher methods, LAL\u0027s `execute` and\nprivate methods, and MAL companions.\n\nPer-*statement* tables are deliberately not emitted outside MAL\u0027s expression codegen. The scan\nthat produces them marks boundaries at stores to a result slot; LAL and OAL bodies are largely\nvoid invocations that store nothing there, so the numbers came out as statement **ordinals**\n(1, 2, 3…) — not lines in any file. Emitting a wrong line is worse than emitting none.\n\n#### Line lookup: an identifier boundary, and two hand-counted envelopes deleted\n\n`lineOfMethod` matched a declaration with `contains(name + \"(\")`, which also accepts a longer\nmethod whose name ENDS with the wanted one. `serialize` is a suffix of `deserialize` and OAL\ndeclares both on every metrics class; it resolved correctly only because the template list happens\nto emit the shorter one first, and nothing said that ordering was load-bearing. Operator-authored\nOAL reaches the same shape — metrics `cpm` and `commando_cpm` in one scope give `doCpm` and\n`doCommandoCpm` on the shared dispatcher. The match now requires a non-identifier character before\nthe name.\n\nMAL still computed two signature lines by counting its own source envelope: `10 + closures +\ninjection` for `run()`, and a bare `9` for a filter class. Both are gone, replaced by the same\nsearch. The filter constant had no artifact-resolving test at all — the branch that varied the\nother one (`SW_DSL_DEBUGGING_INJECTION_ENABLED`) never runs in CI — so an envelope edit shifted\nevery filter frame silently. A guard was needed with the change: statement lines are counted\nforward from the signature, so an unresolved signature (`-1`) turns positive from the third\nstatement on and would have slipped past the existing per-entry bounds check. It now emits no table\nrather than a wrong one.\n\n#### Breaking change: `HierarchyRuleProvider` SPI\n\n```java\n// before\nMap\u003cString, BiFunction\u003cService, Service, Boolean\u003e\u003e buildRules(Map\u003cString, String\u003e ruleExpressions);\n// after\nMap\u003cString, BiFunction\u003cService, Service, Boolean\u003e\u003e buildRules(\n    Map\u003cString, String\u003e ruleExpressions, Map\u003cString, Integer\u003e ruleLines);\n```\n\nA `default` bridge was considered and rejected: it would leave any implementation that didn\u0027t\noverride the new method silently producing `_Lunknown_` classes — exactly the bug being fixed.\nThird-party implementations (if any exist) should adopt the new signature and supply the line map.\n\n- [x] Add a unit test to verify that the fix works.\n- [x] Explain briefly why the bug exists and how to fix it.\n\n#### Tests\n\nEvery new test drives the **production loader or generator** and reads back the **real artifact**\n(class name, `SourceFile`, `LineNumberTable`) — none injects a synthetic coordinate, which is how\nthe missing coordinates went unnoticed in the first place. Each assertion was mutation-checked:\nreverting the production change fails the test.\n\n- `OALSourceAttributionTest` (new, 5) — generates through `OALClassGeneratorV2` and asserts each\n  metrics class names its own statement line, the dispatcher names the file *without* one (one\n  dispatcher spans every metric of a scope, so no single line is true for the class), the builder\n  carries provenance but no line numbers, and every templated method carries exactly one\n  `LineNumberTable` entry landing on its own declaration. OAL is the only DSL whose bodies come\n  from FreeMarker rather than its own codegen, so `lineOfMethod` must find a signature it did not\n  write — and a miss there is silent by design.\n- `HierarchyProviderCoordinateTest` (+2) — asserts the compiled class is named\n  `hierarchy_definition_L2_lower_short_name`, and forces a throw from inside a generated rule to\n  assert the **JVM-reported frame** reads `(hierarchy-definition.yml:7)….java`.\n- `DslGeneratedFileWriterLineOfMethodTest` (new, 5) — pins the identifier boundary with the real\n  colliding pair, and that the answer no longer depends on declaration order.\n- `MalFilterLineAttributionTest` (new, 3) — resolves the filter class\u0027s `LineNumberTable` against\n  the generated source that was written, the artifact the deleted constant never had a test for.\n- `RuleKeyTest` (+3) — the boot and hot-update spellings are one key, one registry entry, and only\n  a YAML extension is stripped.\n- `RuleSourcePathTest`, `RulesLoaderTest`, `LALConfigsSourceCoordinateTest`,\n  `LALConfigsLoaderTest`, `ZabbixConfigSourceCoordinateTest`, `ZabbixConfigsLoaderTest`,\n  `ZabbixGeneratedClassCoordinateTest`, `DslYamlLineIndexKeyLinesTest`,\n  `MalLineAttributionTest`, `MalCompanionSourceTest`, `MalClosureLineAttributionTest`,\n  `LALSourceFileResolvesTest`, `LALSourceAttributionScriptTest`.\n\n#### Operator-visible: generated class names change\n\nA generated class\u0027s stem is the rule file\u0027s path, with the catalog kept only where the class\u0027s\npackage does not already imply it. MAL\u0027s catalogs share one `rt` package and two of them ship a\n`vm.yaml`, so MAL gains it: `vm_L25_cpu_total_percentage` becomes\n`otel_rules_vm_L25_cpu_total_percentage`. LAL has one catalog and its own package, so its names are\nunchanged at `default_L3_default` — `lal/` appears in `SourceFile`, where it is a path an operator\nopens, and not in the name, where it would only repeat the package. Nothing addresses these classes\nby name (generated, loaded reflectively, never named in configuration), but they appear in stack\ntraces, `SW_DYNAMIC_CLASS_ENGINE_DEBUG` dumps and dsl-debugging output, so saved greps on MAL names\nneed updating."
    },
    {
      "commit": "ec1f9a3c98ddf7bcfc82e50d4580a10228ea0703",
      "tree": "08675fa6b21800f98dfac9dbce3eaa1a842d956e",
      "parents": [
        "a2498aad765c58e0864fef74771bb437059c6ec4"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sun Aug 09 16:25:53 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Aug 09 16:25:53 2026 -0700"
      },
      "message": "Fix generated-class source attribution in MAL, LAL and OAL (#13971)\n\nWhen generated DSL code throws, the stack frame should name the file it came\nfrom, the line inside that file, and the line of the rule that produced it.\nAll three were broken, in eight places across three compilers, each producing a\nnumber that was wrong and looked right.\n\n  at ...rt.envoy_ca_L41_service_listener_ssl_ca_expiration_seconds.run(\n         envoy_ca_L41_service_listener_ssl_ca_expiration_seconds.java:12)\n                  |                                              |      |\n       envoy-ca.yaml line 41                          a real file    line 12\n\n- The _L\u003cn\u003e_ segment was the rules-list INDEX, not a line, so every file\u0027s\n  first rule read L0. It now carries the rule\u0027s real YAML line.\n- SourceFile named a file that was never written, so source-attach could not\n  resolve a frame regardless of the line. It now names the sidecar on disk.\n- LineNumberTable held statement ORDINALS, matching neither the YAML nor the\n  generated source. MAL now maps each statement to its real sidecar line.\n\nFixing any two of the three leaves the frame useless, which is why the class\nnaming issue is part of this rather than cosmetic.\n\nClosure companions were the gap: a companion always CLAIMED a source file,\nbecause Javassist stamps SourceFile unconditionally, but the file was never\nwritten -- 84 dangling references in network-profiling alone. Each now writes\nits own sidecar and carries one entry at its SAM signature. One entry is\nderived, not conceded: the statement scanner marks boundaries at stores to a\nresult slot, which a closure body never makes.\n\nLAL and OAL had the same defect and are fixed the same way, going from 0/48\nresolvable to 48/48 for LAL. Their line tables are REMOVED rather than\ncorrected: their statements are void invocations that store nothing, so no\nsound boundary detector exists, and an ordinal that resolves is worse than an\nabsent attribute. A single signature entry for them is a follow-up.\nHierarchy and OAL\u0027s metrics-builder write no sidecar at all, so their\nSourceFile still addresses nothing; both are recorded rather than half-fixed.\n\nBoth sidecar writers also moved off a platform-default FileWriter with a\nnon-ASCII header -- the pairing that produced MalformedInputException for MAL\non this branch.\n\nScope is deliberately the error path only. No API, no payload, no format\nchange: the dsl-debugging probes, records and UI are untouched, and their\nline numbers come from parse-time tokens that never involved bytecode."
    },
    {
      "commit": "a2498aad765c58e0864fef74771bb437059c6ec4",
      "tree": "e020105c63e94d8863e5a49afd1c054f8a23fa62",
      "parents": [
        "c59f7b410b20596a1effa09161d334cb081eea33"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Sat Aug 08 00:00:19 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 08 00:00:19 2026 +0800"
      },
      "message": "feat(oap): twelve Node.js runtime meters + pin apache agent #143 (#13970)"
    },
    {
      "commit": "c59f7b410b20596a1effa09161d334cb081eea33",
      "tree": "94134818821bc90427b1fd2655ecdc28c8df6cce",
      "parents": [
        "768a954fe913df5bd7833569ef91a268e0c2df0b"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Aug 06 20:48:46 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 07 11:48:46 2026 +0800"
      },
      "message": "Support runtime rule hot-update and DSL debugging for meter-analyzer-config (#13969)\n\nSupport runtime rule hot-update and DSL debugging for meter-analyzer-config\n\nBring the meter-analyzer-config catalog to parity with otel-rules. Native\nmeter (MeterReportService) rules now load through the same Rules/Rule\npipeline otel-rules uses, so they participate in RuleSetMerger, are recorded\nin StaticRuleRegistry, support the optional layerDefinitions block, and\ngenerate source-named expression classes instead of falling back to\nMalExpr_\u003cN\u003e. MeterProcessService implements MalConverterRegistry and\npublishes MalStaticBindingHook at boot, so a meter rule can be added,\noverridden or inactivated at runtime, and attached to a DSL debug session,\nwithout restarting the OAP. The internal MeterConfig / MeterConfigs model is\nremoved in favour of the shared one.\n\nAnalyzerModuleProvider now declares StorageModule, matching every other\nRules.loadRules caller: meter rule loading moved to start() because the\nmerge consults the runtime-rule DB override resolver, which needs a live\nstorage module. Without it the module sort placed agent-analyzer ahead of\nstorage and an operator\u0027s meter-rule override was silently dropped at boot.\n\nAdds a runtime-rule meter e2e case (readiness plus five capability phases:\nbundled visibility, hot add, structural edit with converter replacement, DSL\ndebug on a bundled rule, and inactivate with converter removal) and a unit\ntest for the converter registry contract.\n\nBehaviour change: an entry in meterAnalyzerActiveFiles\n(SW_METER_ANALYZER_ACTIVE_FILES) with no matching rule file now fails OAP\nstartup instead of being silently ignored, matching otel-rules.\n\nAlso removes the checkstyle.skip exemption from library-pprof-parser - the\nonly module in the repo carrying one - and fixes the two violations it was\nhiding."
    },
    {
      "commit": "768a954fe913df5bd7833569ef91a268e0c2df0b",
      "tree": "e0464fe5343f6b9447d25a090ad918598d560500",
      "parents": [
        "c69396746755f53581f74a33fc1ba58c5285cd6f"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Wed Aug 05 22:09:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 05 22:09:56 2026 +0800"
      },
      "message": "Make the PagerDuty Events API v2 endpoint configurable.  (#13968)"
    },
    {
      "commit": "c69396746755f53581f74a33fc1ba58c5285cd6f",
      "tree": "eb49add4dc16c3452cd390fb30eb10fc816525e8",
      "parents": [
        "c66a476a994a2ce9c89cc955166420f9f3259a0a"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Tue Aug 04 21:29:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 04 21:29:46 2026 +0800"
      },
      "message": "Add the MAL functions tests back. (#13967)\n\n- ScopeTest: compare the produced/expected MeterEntity key sets and iterate over\n  the expected map so a missing or extra entity fails the test.\n- K8sTagTest: capture and restore the KubernetesServices/KubernetesPods enum\n  singletons so the mocked instances do not leak into other tests.\n- DecorateTest: move MeterEntity naming-control setup into @BeforeAll/@AfterAll\n  and reset it so the global state is not leaked."
    },
    {
      "commit": "c66a476a994a2ce9c89cc955166420f9f3259a0a",
      "tree": "87c1d63a4cb65bd66aad205a6e6ce57d965f81d9",
      "parents": [
        "be0383a4fd87111a781175f2633c97c2fe9cca99"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Fri Jul 31 22:52:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 22:52:56 2026 +0800"
      },
      "message": "Support BanyanDB\u0027s group-scoped trace retention pipeline (#13965)\n\nBanyanDB can now run a sampler plugin inside the data node during compaction, deciding per whole trace whether to keep it. This wires OAP up to configure that: the trace and zipkinTrace groups gain a pipeline block in bydb.yml, which OAP pushes onto the BanyanDB group as a TracePipelineConfig.\n\nUnlike the ingest-side server-side trace sampling, this runs AFTER storage, so it reclaims space already written and sees the whole trace rather than one segment as it arrives. The two are independent gates, so enabling both multiplies the drop rate. Disabled by default.\n\nConfig notes worth knowing:\n\n- The grace windows use -1 for \"inherit the data node default\" (30s merge, 5m finalize), because the node treats any non-positive grace as unset, so 0 cannot mean \"no grace\" here.\n- enabledEvents accepts a comma-separated string as well as a YAML block list, so it can be set from the environment. Handling only the list form left the events empty, and the node reads an empty list as MERGE for backward compatibility, so asking for FINALIZE would silently have got MERGE with no error to point at.\n- A plugin\u0027s config is passed through verbatim as a protobuf Struct. Nested lists and objects, such as keepTagRules, now survive the loader as real ListValue/Struct instead of being flattened to a string by String.valueOf, and scalars keep their JSON type so a float such as healthySampleRate is not coerced back to a string.\n- A blank value in bydb.yml (a key with nothing after it) aborted startup with an opaque NullPointerException from java.util.Properties, which rejects nulls. Blank entries are now skipped and leave the field at its default, matching what omitting the line does.\n\nThe proto submodule moves to 8fb4409, which is where TracePipelineConfig and SamplerPlugin live; without it the storage plugin does not compile.\n\nFour e2e cases cover the feature as two controlled pairs, one per schema: the same mocked data and thresholds, differing only by a keepTagRules entry, asserting opposite verdicts. Each case walks the whole chain — OAP resolves the placeholders, pushes the config onto the group, the data node loads the .so from the carrier\u0027s trusted dir with no load failures, the data is queryable, and then it is dropped (or kept) once past the merge grace. Locally 20/20 against the published d552528a carrier.\n\nThe BanyanDB plugin:https://github.com/apache/skywalking-banyandb/pull/1234"
    },
    {
      "commit": "be0383a4fd87111a781175f2633c97c2fe9cca99",
      "tree": "2fd74b9b2b01a0162c1f7c1dee34bb9078726060",
      "parents": [
        "dddc3b51be9d027755d48e99f72b362e969ccecd"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Jul 29 07:51:39 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 07:51:39 2026 +0800"
      },
      "message": "Always send an explicit LIMIT on BanyanDB queries (#13961)\n\nBanyanDB applies its own default limit to any query that carries none --\n100 rows for measures, 20 for streams/traces -- and applies it after\nGROUP BY, so an over-long result set is silently truncated rather than\nrejected.\n\nOAP never sent a limit on several read paths, so an entity-scoped metrics\nquery returned at most 100 data points regardless of the requested range:\na 4-hour minute-step read rendered only its first 100 minutes and the rest\nshowed as empty, even though DurationUtils.MAX_TIME_RANGE allows up to 500\nsteps. The same cap silently shortened topology relation maps, instance\nand process metadata lists, profiling thread snapshots and eBPF task lists.\n\nEvery BydbQL query now leaves OAP with an explicit LIMIT:\n\n- the entity-scoped metrics read sends the exact number of assembled\n  duration points, the same row set the ES/JDBC DAOs fetch by explicit id;\n- ad-hoc SELECT TOP sends its own N;\n- anything that does not paginate itself falls back to the configured\n  resultWindowMaxSize (default 10000) via Conditions#limitIfAbsent, applied\n  in the stream/measure/trace query helpers that every DAO funnels through.\n\nThe fallback is spliced in at the start of the pagination tail rather than\nappended, so it lands ahead of an OFFSET that was set first and keeps\nWITH QUERY_TRACE positioned as the grammar requires.\n\nES and JDBC storage were never affected -- both fetch metrics rows by\nexplicit document id."
    },
    {
      "commit": "dddc3b51be9d027755d48e99f72b362e969ccecd",
      "tree": "dfa368cb1b273fb4019f5e2509d7dacb9125a973",
      "parents": [
        "2822f125ae3ec397c5339ba172aee9ca3a09245f"
      ],
      "author": {
        "name": "kezhenxu94",
        "email": "kezhenxu94@apache.org",
        "time": "Fri Jul 24 20:19:39 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 24 20:19:39 2026 +0800"
      },
      "message": "Support Elasticsearch 9.x as storage (#13957)\n\nThe ES client version gate capped at major \u003d\u003d 8, so a server reporting\nmajor 9 fell through to UnsupportedOperationException and OAP refused to\nstart against an Elasticsearch 9 cluster. ES 9 keeps the same REST\nsurface the ES 8 path already uses (typeless document writes and\ncomposable index templates), so admit major \u003e\u003d 8 to that path.\n\nAdd ES 9.3.0 to the module IT (ElasticSearchIT) and a new Storage ES\n9.3.0 e2e case alongside the existing 8.18.8 coverage; update the storage\ndocs and changelog."
    },
    {
      "commit": "2822f125ae3ec397c5339ba172aee9ca3a09245f",
      "tree": "c8d0c2b139571cd34d903f731123b6bd990ea0ad",
      "parents": [
        "f9edc58aef0b5eb50fd5dd477010f55156651858"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Tue Jul 21 14:17:03 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 21 14:17:03 2026 +0800"
      },
      "message": "Route LAL rules within a layer by input type; add envoy-als-tcp rule (#13955)"
    },
    {
      "commit": "f9edc58aef0b5eb50fd5dd477010f55156651858",
      "tree": "8895c82ca3e9a01f071c6a87988ac91e71a1aead",
      "parents": [
        "4fae3c6a65ce51d0c66d983244fc3b28de7ba311"
      ],
      "author": {
        "name": "Wan Kai",
        "email": "wankai123@foxmail.com",
        "time": "Thu Jul 16 14:38:51 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jul 16 14:38:51 2026 +0800"
      },
      "message": "Clear Go e2e test-fixture CVE Dependabot alerts (x/net + Go stdlib) (#13951)"
    },
    {
      "commit": "4fae3c6a65ce51d0c66d983244fc3b28de7ba311",
      "tree": "a5cbc6f412833fd2e4f35a7966eb99ccc18bbe0b",
      "parents": [
        "5f6496e72c9acab1ce6ef107f3a168f6eaff8f40"
      ],
      "author": {
        "name": "mrproliu",
        "email": "741550557@qq.com",
        "time": "Wed Jul 15 20:49:50 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 15 13:49:50 2026 +0100"
      },
      "message": "Some enhancement check for bydbQL (#13949)"
    },
    {
      "commit": "5f6496e72c9acab1ce6ef107f3a168f6eaff8f40",
      "tree": "e50b25091f33de51ef74a536561f5f0f8a028173",
      "parents": [
        "46129f18e815829ea14afce9a013bae7d8dfdc66"
      ],
      "author": {
        "name": "mrproliu",
        "email": "741550557@qq.com",
        "time": "Wed Jul 15 12:58:50 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 15 12:58:50 2026 +0800"
      },
      "message": "Migrate all BanyanDB storage read queries from the typed query-builder API to BydbQL (#13947)"
    },
    {
      "commit": "46129f18e815829ea14afce9a013bae7d8dfdc66",
      "tree": "6fa138d949f9975636e7c54a3ddf066cabe80a91",
      "parents": [
        "432d55f2a7de58d797a382e7df823edfdb745358"
      ],
      "author": {
        "name": "kezhenxu94",
        "email": "kezhenxu94@apache.org",
        "time": "Mon Jul 13 14:32:31 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 13 14:32:31 2026 +0800"
      },
      "message": "Bump netty/jackson/commons-codec to clear CVE alerts on shipped OAP jars (#13944)\n\n- netty 4.2.12.Final -\u003e 4.2.15.Final (root pom netty.version)\n- jackson 2.18.6 -\u003e 2.18.8 (oap-server-bom)\n- jackson-databind 2.16.0 -\u003e 2.18.8 (realign to the rest of the jackson\n  family, which had moved ahead while databind was left behind)\n- commons-codec 1.11 -\u003e 1.13 (oap-server-bom)\n\nAll versions are JDK 11 compatible (SkyWalking targets maven.compiler.release\u003d11).\n\nUpdate dist-material/release-docs/LICENSE and .licenserc.yaml to match the\nbumped dependency versions (the CI dependency-license check regenerates\nLICENSE and fails on any drift).\n\nSigned-off-by: kezhenxu94 \u003ckezhenxu94@apache.org\u003e"
    },
    {
      "commit": "432d55f2a7de58d797a382e7df823edfdb745358",
      "tree": "6c7131b8a87c5cb6ae347af8a3596522a9bb64ee",
      "parents": [
        "585d195e79b665ce58ac108d325fa2f267a550af"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Jul 07 20:51:47 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 07 20:51:47 2026 +0800"
      },
      "message": "Fix MQE top_n raising a raw storage IO exception for an invalid attribute (#13940)\n\nAn MQE top_n(metric, N, order, attrX\u003d\u0027value\u0027) whose attribute is not a queryable\ncolumn of the metric reached the storage engine with a tag the measure does not\ndefine and failed there, surfacing the opaque \"Internal IO exception, query\nmetrics error.\". Attribute columns (attr0..attrN) exist only on decorated metrics\n(service_*/endpoint_*/kubernetes_service_*, set to the layer via OAL .decorator())\nand the MAL meter base; relations and database/cache/mq access carry none.\n\nMQEVisitor now validates each attribute key against the metric\u0027s registered\nqueryable columns before the storage call and raises IllegalExpressionException\n(naming the attribute and metric), which the existing catch turns into a\ndescriptive MQE error instead of the opaque storage exception."
    },
    {
      "commit": "585d195e79b665ce58ac108d325fa2f267a550af",
      "tree": "19ccefe21dd61818a695d1f1a82577e486fdb7f8",
      "parents": [
        "5884dc8bae32d7529b37e0ee788a107ed1348bf5"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Jul 03 15:50:06 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 03 15:50:06 2026 +0800"
      },
      "message": "Surface LAL drop reason in DSL live-debugging (#13937)"
    },
    {
      "commit": "5884dc8bae32d7529b37e0ee788a107ed1348bf5",
      "tree": "f497f70fa7fce05c3d6b07a6f5d50bdfdef5e7cc",
      "parents": [
        "1432e5eeb20ce93a16978200ace289949b94b947"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Jul 03 08:32:21 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 03 08:32:21 2026 +0800"
      },
      "message": "Support LAL json{} parsing JSON delivered in text log bodies; fix abortOnFailure wiring and leak-probe timing (#13936)\n\nThe OTLP log receiver delivers every string body as a text body, even JSON-shaped ones, while `json {}` read only the JSON body case — so `json {}` rules on OTLP-fed layers silently aborted. `json {}` now reads the JSON body first and, when it is empty, tries the text body as JSON. On a successful text-fallback parse the matching rule\u0027s context input is swapped to a copy with a JSON body, so that rule persists the log with content type `JSON`; the shared input is never mutated, and other rules analyzing the same log still see the original text body. Design discussion is summarized in the updated [`lal.md` `json` section](https://github.com/apache/skywalking/blob/feat/otlp-log-json-body/docs/en/concepts-and-designs/lal.md#json) and [`log-otlp.md`](https://github.com/apache/skywalking/blob/feat/otlp-log-json-body/docs/en/setup/backend/log-otlp.md).\n\nThe DSL flag was parsed into the rule model but never emitted into the generated code, so `json {}` / `yaml {}` / `text { regexp }` always used the built-in default and `abortOnFailure false` had no effect (for all three parsers, including the regexp case). The compiler now bakes each rule\u0027s flag into the generated parser call (default `true`, as documented, fixed from a latent `false` model default). A parse failure or regexp non-match that aborts the log is reported at WARN, rate-limited to one report per minute per parser with the suppressed count included in the next report; with `abortOnFailure false` the failure is DEBUG-only, the log continues, and `parsed.*` reads fall back to metadata fields instead of NPE-dropping the log. Typed-proto inputs (e.g. Envoy ALS entries hitting the MESH `json {}` routing guard) stay quiet as before."
    },
    {
      "commit": "1432e5eeb20ce93a16978200ace289949b94b947",
      "tree": "6da70b0eaa03b0926844f0e84ef715fc3ccccdd9",
      "parents": [
        "eec76bacbc029e5b9974099cc0d9693841222d56"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Jul 02 21:09:43 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jul 02 21:09:43 2026 +0800"
      },
      "message": "Fix false-positive DSL classloader leak warnings on idle heaps (#13935)"
    },
    {
      "commit": "eec76bacbc029e5b9974099cc0d9693841222d56",
      "tree": "9d12d22c4a357bb9e3139067fb688ec7baa10231",
      "parents": [
        "08b0804be0d41c61c6371383ec5b6e2bde363605"
      ],
      "author": {
        "name": "kezhenxu94",
        "email": "kezhenxu94@apache.org",
        "time": "Tue Jun 30 22:11:37 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 30 22:11:37 2026 +0800"
      },
      "message": "Add TLS support for OAP HTTP/REST servers with cert hot-reload (#13933)\n\nThe gRPC servers already supported TLS, mTLS, and cert reload on rotation.\nThis adds the equivalent for the Armeria-based HTTP/REST servers (core REST /\nGraphQL, sharing REST, admin, PromQL, LogQL, TraceQL, Zipkin query/receiver):\n\n- HTTPServer now reloads the key pair from disk via Armeria\n  TlsProvider.ofScheduled, so rotated certificates (e.g. a refreshed Kubernetes\n  secret) are picked up without restarting the OAP. Previously the cert/key were\n  read once at startup.\n- Every HTTP server exposes the same restSSLEnabled / restSSLKeyPath /\n  restSSLCertChainPath config structure, each with its own dedicated environment\n  variables: SW_CORE_REST_SSL_*, SW_RECEIVER_SHARING_REST_SSL_*,\n  SW_ADMIN_SERVER_REST_SSL_*, SW_PROMQL_REST_SSL_*, SW_LOGQL_REST_SSL_*,\n  SW_TRACEQL_REST_SSL_*, SW_QUERY_ZIPKIN_REST_SSL_*, SW_RECEIVER_ZIPKIN_REST_SSL_*.\n  Each server reads the settings from its own module config.\n- HTTP TLS is server-side only (no mTLS).\n\nAdds HTTPServerTLSTest covering disk load, rotation pickup, and missing files;\nupdates application.yml and the TLS / configuration-vocabulary / changelog docs."
    },
    {
      "commit": "08b0804be0d41c61c6371383ec5b6e2bde363605",
      "tree": "12284a31e8eb923c8a46cc0b8f4dd6b7c4e9aa55",
      "parents": [
        "62423e4dfa63c0dffad021a57c803bfb1c7c6e4f"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Jun 30 16:41:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 30 16:41:46 2026 +0800"
      },
      "message": "Surface BanyanDB config in /debugging/config/dump via a ConfigDumpExtension SPI (#13932)\n\n* Surface BanyanDB config in /debugging/config/dump via ConfigDumpExtension SPI\n\nThe BanyanDB storage config moved to a separate bydb.yml / bydb-topn.yml in\n10.2.0, so a BanyanDB deployment showed an empty storage.banyandb block in the\n/debugging/config/dump admin API while ES/JDBC showed theirs.\n\nAdd a generic ConfigDumpExtension SPI on ServerStatusService that any module\nloading configuration from a secondary file can implement. BanyanDB registers\nan extension that flattens its already-loaded, environment-resolved config into\nstorage.banyandb.* (TopN rules under storage.banyandb.topN.*), merged into the\nsame dump and masked centrally by the existing secret-keyword list. The status\nmodule stays storage-agnostic (dependency arrow plugin -\u003e core); the Horizon UI\nneeds no change since it groups by the first dotted segment.\n\nAdds UTs for the core merge+mask and the flattener, plus a representative\nconfig-dump assertion on the banyandb storage e2e case."
    },
    {
      "commit": "62423e4dfa63c0dffad021a57c803bfb1c7c6e4f",
      "tree": "7be9503837db198e662496a72624ad587aaa932f",
      "parents": [
        "462423a0ca7e28c9e6204ec4ceba06753d77b615"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Jun 30 11:18:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 30 11:18:56 2026 +0800"
      },
      "message": "Decode Istio metadata-exchange peer in Envoy ALS rendering; harden proto-to-JSON (#13931)\n\n**Why the bug exists.** Envoy `HTTPAccessLogEntry`/`TCPAccessLogEntry` carry the Istio metadata-exchange peer in `common_properties.filter_state_objects`, which is `map\u003cstring, google.protobuf.Any\u003e`. The LAL live-debugger serialized the input via a `JsonFormat` printer built **without** a `TypeRegistry` (`LalPayloadDebugDump`), so it threw `Cannot find type for url: …` and the INPUT sample showed an error envelope instead of the entry. Separately, the LAL output builder\u0027s `bindInput` (which the generated `execute()` calls eagerly, **before** the debug capture) serialized via the bare `ProtoBufJsonUtils.toJSON`; an unregistered injected `Any` there threw and **aborted the whole rule**, dropping the mesh log.\n\n**How it\u0027s fixed.**\n- `LalPayloadDebugDump` now uses a well-known-type `TypeRegistry` plus a sanitizer, so a single un-printable field can no longer blank the whole entry: an unresolvable / no-slash / corrupt-bytes `Any` degrades to an `@unresolved` placeholder, and a non-finite `Value` double (`NaN`/`Infinity`, which `JsonFormat` rejects) is rendered as a string.\n- The predictable Istio peer is decoded into readable metadata (pod / namespace / labels) — legacy Wasm `wasm.*_peer` (`Any{BytesValue}` → FlatBuffer, reusing the existing `ServiceMetaInfoAdapter`) and modern `*_peer` (`Any{Struct}`) — for both the live-debug INPUT sample and the persisted log `content`, covering HTTP **and** TCP access logs.\n- Decoding is wired through a new `LalInputDebugRenderer` SPI (`EnvoyAlsHttpDebugRenderer` / `EnvoyAlsTcpDebugRenderer`), so `log-analyzer` reaches the receiver-side decoders without depending on the Envoy receiver — mirroring the existing `LALSourceTypeProvider` seam."
    },
    {
      "commit": "462423a0ca7e28c9e6204ec4ceba06753d77b615",
      "tree": "d2f720d98f8eb30cbeed64d0a39e577554eddfc7",
      "parents": [
        "bb16533009a597dbb41ab6f013ac300509abbb3e"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Tue Jun 30 10:01:37 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 30 10:01:37 2026 +0800"
      },
      "message": "Add Node.js runtime meter support and e2e validation (#13930)\n\nAdd nodejs-runtime MAL rules, documentation, e2e assertions, and pin\nSW_AGENT_NODEJS_COMMIT to apache/skywalking-nodejs master @ 36df516\n(merged apache/skywalking-nodejs#139)."
    },
    {
      "commit": "bb16533009a597dbb41ab6f013ac300509abbb3e",
      "tree": "c8c08f4f9905713179614e6bad856fea07e13a64",
      "parents": [
        "4226f14e908462d92139ae0974164b5fb0ab52d0"
      ],
      "author": {
        "name": "songzhendong",
        "email": "xiaodong12315@qq.com",
        "time": "Thu Jun 25 10:34:00 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 25 10:34:00 2026 +0800"
      },
      "message": "Add PHP runtime PHM meter analyzer, e2e, and documentation. (#13928)\n\nIntroduce php-runtime.yaml MAL rules for six instance_php_* meters, MAL tests,\nPHP e2e meter assertions, and backend docs. Pin SW_AGENT_PHP_COMMIT to\napache/skywalking-php@de311c9 (PHM #145). Use metrics_report_period\u003d31 in e2e\nphp.ini so meter gRPC streams idle-close and OAP persists PHM data."
    },
    {
      "commit": "4226f14e908462d92139ae0974164b5fb0ab52d0",
      "tree": "dfc7b6cd7e3339e424230e2d250120b9bd57ee34",
      "parents": [
        "fe55b90bcf12b7962017ea64086121b8a07c7368"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Jun 24 23:36:38 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 24 23:36:38 2026 +0800"
      },
      "message": "Add POST /inspect/values admin API to read foreign metric values (#13927)\n\nA new admin-only POST /inspect/values reads the VALUES of a metric this OAP does not\ndefine locally (persisted by another OAP), by running the real MQE engine over\ncaller-supplied {valueColumn, valueType} — the value-reading companion to the merged\nGET /inspect/entities foreign path (#13926).\n\nA request-scoped InspectQueryContext ThreadLocal makes the foreign metric look\nregistered to every read path (provide-if-absent — the local catalog always wins):\nValueColumnMetadata resolves its value column / type / scope, and the storage location\nregistries resolve where it lives — MetadataRegistry synthesizes a BanyanDB measure\nschema, IndexController resolves the ES metrics-all index, TableHelper probes the JDBC\nfunction tables. The storage read paths need no per-DAO special-casing; the response is\nthe native MQE ExpressionResult. Verified end-to-end across banyandb/es/postgresql."
    },
    {
      "commit": "fe55b90bcf12b7962017ea64086121b8a07c7368",
      "tree": "d35a0e965e2f821333e28dd4068b44bb8f7fdc63",
      "parents": [
        "f409ed7be71f4c3477ce07681373029facbf3036"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Wed Jun 24 09:19:23 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 24 09:19:23 2026 +0800"
      },
      "message": "Extend `GET /inspect/entities` to inspect foreign metrics persisted by any OAP (#13926)\n\n### Extend `GET /inspect/entities` to inspect a metric persisted by any OAP (foreign metric)\n\n`/inspect/entities` previously enumerated entities only for metrics **defined on the queried OAP**. This extends it so a metric persisted by *any* OAP — one this node never loaded the OAL/MAL/runtime-rule for — can be inspected when the caller supplies the metric\u0027s `valueColumn` + `valueType`.\n\n- The storage backend resolves the physical index/table/group from its **own running config** — no DB schema / table-metadata read:\n  - **Elasticsearch** — merged `metrics-all` index + `metric_table` discriminator.\n  - **JDBC** — probes the node\u0027s function tables by the `table_name` discriminator.\n  - **BanyanDB** — synthesizes a read-only measure schema.\n- `entity_id` is decoded **structurally** (service / 2nd-level / relations) with a generic `name` leaf; scope is no longer required for the foreign path.\n- Locally-defined metrics keep the **exact** field names, scope, and `mqeEntity` (behavior unchanged).\n- Reads are optimistic — errors surface to the caller; a metric unknown locally without `valueColumn`/`valueType` returns a clear `400` steering the caller to the foreign path.\n\n`swctl admin inspect entities` gains `--value-column` / `--value-type` (apache/skywalking-cli#230); `SW_CTL_COMMIT` is bumped to the cli commit that ships them, and a 2-OAP inspect e2e (aware + foreign) is wired across BanyanDB / ES / PostgreSQL."
    },
    {
      "commit": "f409ed7be71f4c3477ce07681373029facbf3036",
      "tree": "d8ac8f587469a336854e68c559ca00c750d321ad",
      "parents": [
        "799bb76c044dbfccdff473feb436021aefe07972"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Tue Jun 23 09:37:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 23 09:37:46 2026 +0800"
      },
      "message": "Remove the always-on alarm-to-event conversion (EventHookCallback) (#13925)\n\nA triggered alarm is no longer synthesized into the events pipeline as an\nAlarm/AlarmRecovery event; events now originate only from real event sources\n(agents, SkyWalking CLI, Kubernetes Event Exporter). Alarms remain available\nthrough the alarm store (getAlarm/queryAlarms) and the configured alarm hooks.\n\n- Delete EventHookCallback and its unconditional registration in NotifyHandler.\n- Delete EventHookCallbackTest.\n- Drop the now-dead event-analyzer dependency from server-alarm-plugin.\n- Remove the \u0027Alarm\u0027 Known-Event row from event.md; update the e2e guide recipe.\n- Update the alarm/baseline e2e expected files to assert \u0027events: []\u0027 — the\n  alarm now correlates no synthetic event (swctl \u0027alarm ls\u0027 still projects the\n  events field, so the expectation must assert the empty list).\n- Add a CHANGES entry."
    },
    {
      "commit": "799bb76c044dbfccdff473feb436021aefe07972",
      "tree": "f4aacfa7f487834c8c2cb6111d087450b8fc3722",
      "parents": [
        "e1acb44d1a939bc2155e1583f5d4d41fe9825907"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sat Jun 20 18:24:50 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jun 20 18:24:50 2026 +0800"
      },
      "message": "docs: list Java 25 in backend runtime requirement (#13922)"
    },
    {
      "commit": "e1acb44d1a939bc2155e1583f5d4d41fe9825907",
      "tree": "d1b8ea83c84d4edbba712ccc487cb918ae820de8",
      "parents": [
        "dcfb07014ea5b6813aed214ba34e6230678d37a3"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Sat Jun 20 09:13:59 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jun 20 09:13:59 2026 +0800"
      },
      "message": "Clear 3 security alerts: protobuf e2e fixture CVE-2026-0994 + histogram count narrowing (#13921)\n\n* Clear 3 security alerts: protobuf e2e fixture CVE + histogram count narrowing\n\n- Dependabot CVE-2026-0994: bump the Airflow e2e mock\u0027s pinned protobuf\n  4.25.8 -\u003e 5.29.6 (no 4.x patch exists) and opentelemetry-proto 1.24.0 -\u003e 1.28.0\n  (its protobuf\u003c5.0 cap was the blocker). CI-only test fixture, never shipped;\n  grpcio/flask unchanged.\n- CodeQL java/implicit-cast-in-compound-assignment: widen the cumulative `count`\n  accumulator from int to long in Sum/AvgHistogramPercentileFunction. `count +\u003d\n  value` silently narrowed a long bucket-count sum back to int; `total` was\n  already long."
    },
    {
      "commit": "dcfb07014ea5b6813aed214ba34e6230678d37a3",
      "tree": "e10f404afb1c266512f7a761351defea14849a6a",
      "parents": [
        "6cf80750ed9fa23b42fc73524096030f953701c7"
      ],
      "author": {
        "name": "Marc Navarro",
        "email": "marcnavarro@tetrate.io",
        "time": "Fri Jun 19 08:36:22 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 19 14:36:22 2026 +0800"
      },
      "message": "Fix custom layers: MAL v2 Layer.NAME compilation + layer-extensions.yml jar shadowing (#13918)\n\n**Bug 1 — MAL v2 compiler cannot compile a custom-layer reference**\n\nA custom layer has no generated `Layer.*` static field — it lives only in the name registry — so referencing it in a MAL expression failed v2 code generation. The natural form `service([\u0027svc\u0027], Layer.IOT_FLEET)` parses as the static-field `enumRef` (`IDENTIFIER DOT IDENTIFIER`, exactly like `Layer.GENERAL`), and codegen emitted it verbatim as a `Layer.IOT_FLEET` field access — a field that does not exist on `Layer` — so Javassist failed to compile the generated source.\n\nFix: `MALMethodChainCodegen` now lowers every `Layer.NAME` static-field reference to a runtime `Layer.nameOf(\"NAME\")` registry lookup, scoped to `Layer` only (via `MALCodegenHelper.LAYER_ENUM_TYPE`). `Layer` is a registry-backed type, not a Java enum, and `Layer.nameOf` resolves both built-in and custom layers by name; for a built-in this is behavior-preserving, because `Layer.nameOf(\"GENERAL\")` returns the same instance as the `Layer.GENERAL` field. The other `ENUM_FQCN` types (`DetectPoint`, `DownsamplingType`, `TimeUnit`, `K8sRetagType`) are real Java enums with no `nameOf(String)` and keep their direct static-field reference. A custom layer is therefore referenced exactly like a built-in one, with no grammar / AST / parser change. `docs/.../mal.md` is updated to the `Layer.NAME` form.\n\nTests (`MALClassGeneratorTest`): a custom-layer field form lowers to `Layer.nameOf(\"...\")` and compiles; a built-in field form lowers identically; a non-`Layer` enum (`DetectPoint`) keeps its direct field access. All 1350 bundled-rule execution tests pass — every built-in `Layer.*` reference now routes through `nameOf` and resolves to the same layer (no rule used a custom layer before, which is why CI never caught it).\n\n\u003e _Note: an earlier revision of this PR fixed only the explicit `Layer.nameOf(\u0027NAME\u0027)` method form via a parser reinterpretation (`EnumStaticCallArgument`). That was superseded by the field-form lowering above — the field form is the natural, documented-as-built-in syntax and needs no grammar/AST special-casing. Neither form had shipped, so there is no compatibility concern._\n\n**Bug 2 — `layer-extensions.yml` bundled in the jar shadows the operator\u0027s `config/` copy**\n\n`layer-extensions.yml` (operator-managed, documented as living in `config/`) was packaged inside `skywalking-oap.jar` and not shipped to the distribution `config/`. The launch script (`dist-material/bin/oapService.sh:38-41`) prepends every `oap-libs/*.jar` to `CLASSPATH`, leaving `config/` last, so `ResourceUtils.read(\"layer-extensions.yml\")` → `getClassLoader().getResource(...)` deterministically resolved the empty jar-bundled template (`layers: []`) and silently ignored the operator\u0027s file — custom layers declared there never registered.\n\nFix: add `layer-extensions.yml` to the `maven-jar-plugin` `\u003cexcludes\u003e` (`oap-server/server-starter/pom.xml`) and to the assembly `\u003cincludes\u003e` (`apm-dist/src/main/assembly/binary.xml`), so it follows the same exclude-from-jar + copy-to-`config/` packaging as every other operator-editable config. Verified by rebuilding `skywalking-oap.jar` and confirming the file is no longer present."
    },
    {
      "commit": "6cf80750ed9fa23b42fc73524096030f953701c7",
      "tree": "d4b5c62aae06c90ad736f4144d4ac3810565e31f",
      "parents": [
        "95a296e2c810e6280b16975dd411e9c595a16836"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Jun 19 13:40:19 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 19 13:40:19 2026 +0800"
      },
      "message": "Migrate Consul client to kiwiproject fork to clear okhttp CVE-2021-0341 (#13920)\n\n* Migrate Consul client to maintained kiwiproject fork (0.9.0) to clear okhttp CVE\n\nMigrate the Consul cluster and configuration plugins from the abandoned\ncom.orbitz.consul:consul-client 1.5.3 to the maintained fork\norg.kiwiproject:consul-client 0.9.0 to clear CVE-2021-0341 (okhttp 3.14.9).\n\n- Pin to 0.9.0: the newest fork release still built for JDK 11 bytecode\n  (1.0.0+ is Java 17, which SkyWalking still targets via maven.compiler.release\u003d11).\n- BOM: bump okhttp 3.14.9 -\u003e 4.12.0 (clears the CVE, Java-8/11 safe); pin\n  jackson-datatype-jdk8/guava to the managed jackson 2.18.6 so the client\n  cannot drag in an off-version.\n- Source change is a package rename (com.orbitz.consul -\u003e org.kiwiproject.consul);\n  plugins use only stable Consul APIs.\n- ITs stay on consul:0.9. Regenerated LICENSE and added .licenserc.yaml mappings."
    },
    {
      "commit": "95a296e2c810e6280b16975dd411e9c595a16836",
      "tree": "b01cfcc066737cb53b08b99f630e2ce2ddf503ea",
      "parents": [
        "277f19bcce913c7aed66c13178d7b29f252ed729"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Fri Jun 19 11:24:25 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 19 11:24:25 2026 +0800"
      },
      "message": "Let Spring Boot manage logback (matched) - clears 4 logback-core CVE alerts (#13916)\n\n#13913 pinned logback-classic to 1.2.13 while Spring Boot kept logback-core at\n1.2.6 (mismatch -\u003e NoSuchMethodError -\u003e lua e2e hang). #13915 fixed the hang by\nadding an explicit logback-core 1.2.13 dep, but that made Dependabot flag\nlogback-core (4 CVEs patched only in logback 1.3.x/1.5.x, which need SLF4J 2.0 /\nJava 17 - unreachable on this Java-8 / Spring Boot 2.5 fixture).\n\nDrop the explicit logback pins entirely and let spring-boot-dependencies manage\nboth logback-classic and logback-core to the same version (1.2.6). Matched\nversions never trigger the NoSuchMethodError, and a BOM-managed (not declared)\nlogback-core is not flagged by Dependabot - so the 4 alerts clear without\nshipping a vulnerable declared dependency, and the lua fix is preserved."
    },
    {
      "commit": "277f19bcce913c7aed66c13178d7b29f252ed729",
      "tree": "196c34512b5a227d4a0b37adf4796ef0eb4fcfad",
      "parents": [
        "7d10e221a243cb3417b08748e6266948db4a8975"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Jun 18 17:07:58 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 17:07:58 2026 +0800"
      },
      "message": "Clear test-fixture CVE Dependabot alerts: drop log4j 1.x + modernize Go fixtures (#13915)\n\n### Clear test-scope CVE Dependabot alerts (log4j 1.x + Go e2e fixtures)\n\nFollow-up to #13913. Clears ~18 of the remaining open Dependabot alerts, all in e2e **test fixtures** (no production code).\n\n**log4j 1.x** — `e2e-service-provider` (2 alerts; log4j 1.x is EOL, one CVE has no patched release):\n- Removed `log4j:log4j` 1.2.17 + `apm-toolkit-log4j-1.x` and `log4j.properties`. The provider already exercises log-to-OAP through **log4j2** (`apm-toolkit-log4j-2.x`, grpc appender) and **logback** in parallel, so log-reporting coverage is preserved. The log4j2 loggers now use the imported `org.apache.logging.log4j.Logger` (no inline FQCN). Dropped the log4j-1.x `fileLogger` items from the filebeat/fluentd expected files.\n\n**Go fixtures** — `grpc`/`golang.org/x/net`/`x/crypto`/`protobuf` (~16 alerts; the patched releases require Go ≥ 1.23):\n- `cases/go/service`: `go 1.24`; x/crypto 0.46, x/net 0.48, grpc 1.79.3, protobuf 1.36.10; Dockerfile base `-go1.19` → `-go1.24`. `SW_AGENT_GO_COMMIT` → `19a9fa9` (the skywalking-go commit that ships the go1.24 images; go1.19 images were dropped). All 5 shared go cases (go/service, profiling/trace/go, pprof/{mysql,es,banyandb}) build from this one Dockerfile.\n- `cases/profiling/ebpf/network`: **migrated off the legacy go2sky SDK to the skywalking-go toolchain agent** (auto-instruments net/http server+client). The app exit span is now auto-instrumented (`GET:/provider`, `GoHttpClient`, layer `Http`, peer `proxy`, http tags, spanid 1/parent 0) — `expected/skywalking-trace.yml` updated, derived from the skywalking-go net/http plugin. The eBPF sampled-record name (`skywalking-\u003cpath\u003e`) is network-derived and unchanged, so the verify query and the 4xx/5xx expectations are untouched."
    },
    {
      "commit": "7d10e221a243cb3417b08748e6266948db4a8975",
      "tree": "d935675f16d46d8f17fc43fbfa6d751d0336edc0",
      "parents": [
        "fe6f04e0ea0d5b7af0fe2be6cc6cad7486815d81"
      ],
      "author": {
        "name": "吴晟 Wu Sheng",
        "email": "wu.sheng@foxmail.com",
        "time": "Thu Jun 18 11:34:51 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 11:34:51 2026 +0800"
      },
      "message": "Clear CVE Dependabot alerts: Curator/ZooKeeper bump, assertj, e2e test fixtures (#13913)\n\nThis clears the actionable, non-Go Dependabot alerts on `master`. (The Go e2e-fixture alerts require a Go 1.24 agent toolchain and are handled separately via skywalking-go image work + an e2e follow-up.)\n\n### Shipped product (oap-server-bom + LICENSE + docs)\n- **Apache Curator `4.3.0` → `5.9.0`** (+ `curator-test`) and **Apache ZooKeeper `3.5.7` → `3.9.5`**, bumped together — Curator 5.x is the line that carries the ZK 3.9.x client. Clears **CVE-2023-44981** (critical). OAP is a ZooKeeper *client* only, so the server-side bug was never reachable, but the bundled jar tripped Dependabot. The cluster-zookeeper and configuration-zookeeper plugins use only stable Curator APIs, so no source changes were required. Operator-facing change: supported ZooKeeper server version is now 3.5+ (3.4.x dropped by Curator 5.x). `dist-material/release-docs/LICENSE` regenerated (curator ×4, zookeeper + jute, audience-annotations); `application.yml` + `backend-cluster.md` updated.\n\n### Build/test scope\n- **assertj-core `3.20.2` → `3.27.7`** — clears CVE-2026-24400 (XXE in `isXmlEqualTo`, unused), test scope.\n\n### e2e test fixtures (`test/e2e-v2`, never shipped)\n- guava → `32.0.0-jre`, kafka-clients → `3.9.2` (+ removed a stale unused `2.4.1` property), log4j-core → `2.25.4`, logback → `1.2.13` (the Java-8 line, not Dependabot\u0027s JDK-11 `1.4.12`), json-path → `2.9.0`, flask → `3.1.3`, protobuf → `4.25.8`."
    }
  ],
  "next": "fe6f04e0ea0d5b7af0fe2be6cc6cad7486815d81"
}
