This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-graalvm-distro.git
The following commit(s) were added to refs/heads/main by this push:
new ee1a103 Scan-based immigration scope detection and staleness tracking
ee1a103 is described below
commit ee1a103716c43ca876ff3716e02b331745b706d4
Author: Wu Sheng <[email protected]>
AuthorDate: Wed Feb 25 12:04:14 2026 +0800
Scan-based immigration scope detection and staleness tracking
Add ImmigrationScopeTest to detect new upstream providers and rule files
after skywalking/ submodule updates. Provider inventory (55 entries) and
rule file inventory (89 entries) serve as the single source of truth.
Expand replacement-source-sha256.properties from 4 to 33 entries,
covering all same-FQCN replacement upstream sources.
Refactor ConfigFieldAccessorTest to derive provider list from
provider-inventory.properties ACCEPTED entries and discover nested
config classes via reflection, eliminating hardcoded lists.
Add ASF license header to native-image.properties.
Add oap-libs-for-graalvm/CLAUDE.md documenting replacement inventory.
---
.../oap-graalvm-native/native-image.properties | 15 ++
.../server/graalvm/ConfigFieldAccessorTest.java | 121 +++++-----
.../oap/server/graalvm/ImmigrationScopeTest.java | 259 +++++++++++++++++++++
.../test/resources/provider-inventory.properties | 108 +++++++++
.../resources/replacement-source-sha256.properties | 66 +++++-
.../test/resources/rule-file-inventory.properties | 127 ++++++++++
oap-libs-for-graalvm/CLAUDE.md | 164 +++++++++++++
7 files changed, 787 insertions(+), 73 deletions(-)
diff --git
a/oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native/native-image.properties
b/oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native/native-image.properties
index 7c14aeb..f53ee5c 100644
---
a/oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native/native-image.properties
+++
b/oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native/native-image.properties
@@ -1 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
Args = -H:ReflectionConfigurationResources=${.}/log4j2-reflect-config.json
diff --git
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ConfigFieldAccessorTest.java
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ConfigFieldAccessorTest.java
index 7e0fea7..67e14b6 100644
---
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ConfigFieldAccessorTest.java
+++
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ConfigFieldAccessorTest.java
@@ -17,6 +17,8 @@
package org.apache.skywalking.oap.server.graalvm;
+import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -24,11 +26,13 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
import java.util.Set;
import org.apache.skywalking.oap.server.library.module.ModuleConfig;
import org.apache.skywalking.oap.server.library.module.ModuleProvider;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -42,70 +46,8 @@ import static org.junit.jupiter.api.Assertions.fail;
*/
class ConfigFieldAccessorTest {
- /**
- * Same provider list as ConfigInitializerGenerator. Each provider's
- * newConfigCreator().type() discovers the config class.
- */
- private static final String[] PROVIDER_CLASSES = {
- "org.apache.skywalking.oap.server.core.CoreModuleProvider",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageProvider",
-
"org.apache.skywalking.oap.server.cluster.plugin.standalone.ClusterModuleStandaloneProvider",
-
"org.apache.skywalking.oap.server.cluster.plugin.kubernetes.ClusterModuleKubernetesProvider",
-
"org.apache.skywalking.oap.server.configuration.configmap.ConfigmapConfigurationProvider",
-
"org.apache.skywalking.oap.server.telemetry.prometheus.PrometheusTelemetryProvider",
-
"org.apache.skywalking.oap.server.analyzer.provider.AnalyzerModuleProvider",
-
"org.apache.skywalking.oap.log.analyzer.provider.LogAnalyzerModuleProvider",
-
"org.apache.skywalking.oap.server.analyzer.event.EventAnalyzerModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.register.provider.RegisterModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.trace.provider.TraceModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.jvm.provider.JVMModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.clr.provider.CLRModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.profile.provider.ProfileModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.asyncprofiler.provider.AsyncProfilerModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.pprof.provider.PprofModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.zabbix.provider.ZabbixReceiverProvider",
- "org.apache.skywalking.aop.server.receiver.mesh.MeshReceiverProvider",
-
"org.apache.skywalking.oap.server.receiver.envoy.EnvoyMetricReceiverProvider",
-
"org.apache.skywalking.oap.server.receiver.meter.provider.MeterReceiverProvider",
-
"org.apache.skywalking.oap.server.receiver.otel.OtelMetricReceiverProvider",
-
"org.apache.skywalking.oap.server.receiver.zipkin.ZipkinReceiverProvider",
-
"org.apache.skywalking.oap.server.receiver.browser.provider.BrowserModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.log.provider.LogModuleProvider",
- "org.apache.skywalking.oap.server.receiver.event.EventModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.ebpf.provider.EBPFReceiverProvider",
-
"org.apache.skywalking.oap.server.receiver.telegraf.provider.TelegrafReceiverProvider",
-
"org.apache.skywalking.oap.server.receiver.aws.firehose.AWSFirehoseReceiverModuleProvider",
-
"org.apache.skywalking.oap.server.receiver.configuration.discovery.ConfigurationDiscoveryProvider",
-
"org.apache.skywalking.oap.server.analyzer.agent.kafka.provider.KafkaFetcherProvider",
-
"org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherProvider",
- "org.apache.skywalking.oap.query.graphql.GraphQLQueryProvider",
- "org.apache.skywalking.oap.query.zipkin.ZipkinQueryProvider",
- "org.apache.skywalking.oap.query.promql.PromQLProvider",
- "org.apache.skywalking.oap.query.logql.LogQLProvider",
- "org.apache.skywalking.oap.query.debug.StatusQueryProvider",
-
"org.apache.skywalking.oap.server.core.alarm.provider.AlarmModuleProvider",
- "org.apache.skywalking.oap.server.exporter.provider.ExporterProvider",
-
"org.apache.skywalking.oap.server.health.checker.provider.HealthCheckerProvider",
- "org.apache.skywalking.oap.server.ai.pipeline.AIPipelineProvider",
- };
+ private static final String PROVIDER_INVENTORY =
"provider-inventory.properties";
- private static final String[] EXTRA_CONFIG_CLASSES = {
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$Global",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$RecordsNormal",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$RecordsLog",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$Trace",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$ZipkinTrace",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$RecordsTrace",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$RecordsZipkinTrace",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$RecordsBrowserErrorLog",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$MetricsMin",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$MetricsHour",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$MetricsDay",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$Metadata",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$Property",
-
"org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig$Stage",
- };
/**
* Fields with custom accessors instead of standard getXxx/isXxx.
@@ -184,12 +126,23 @@ class ConfigFieldAccessorTest {
}
}
+ /**
+ * Loads ACCEPTED providers from {@code provider-inventory.properties},
+ * discovers their config classes via {@code newConfigCreator().type()},
+ * then scans inner classes of each config class for nested config types
+ * (e.g. BanyanDBStorageConfig.Global, .Trace, etc.).
+ */
private Map<String, Class<?>> discoverConfigClasses() throws Exception {
Map<String, Class<?>> configClasses = new LinkedHashMap<>();
- for (String providerClassName : PROVIDER_CLASSES) {
+ List<String> acceptedProviders = loadAcceptedProviders();
+ assertFalse(acceptedProviders.isEmpty(),
+ PROVIDER_INVENTORY + " has no ACCEPTED providers");
+
+ for (String providerClassName : acceptedProviders) {
Class<?> providerClass = Class.forName(providerClassName);
- ModuleProvider provider = (ModuleProvider)
providerClass.getDeclaredConstructor().newInstance();
+ ModuleProvider provider = (ModuleProvider) providerClass
+ .getDeclaredConstructor().newInstance();
ModuleProvider.ConfigCreator<?> creator =
provider.newConfigCreator();
if (creator == null) {
continue;
@@ -197,15 +150,45 @@ class ConfigFieldAccessorTest {
Class<?> configType = creator.type();
if (configType != null) {
configClasses.putIfAbsent(configType.getName(), configType);
+ // Scan declared inner classes that have non-static mutable
fields
+ for (Class<?> inner : configType.getDeclaredClasses()) {
+ if (Modifier.isStatic(inner.getModifiers())
+ && hasNonFinalInstanceFields(inner)) {
+ configClasses.putIfAbsent(inner.getName(), inner);
+ }
+ }
}
}
- for (String className : EXTRA_CONFIG_CLASSES) {
- Class<?> clazz = Class.forName(className);
- configClasses.putIfAbsent(clazz.getName(), clazz);
+ return configClasses;
+ }
+
+ private static boolean hasNonFinalInstanceFields(Class<?> clazz) {
+ for (Field f : clazz.getDeclaredFields()) {
+ if (!Modifier.isStatic(f.getModifiers())
+ && !Modifier.isFinal(f.getModifiers())) {
+ return true;
+ }
}
+ return false;
+ }
- return configClasses;
+ private List<String> loadAcceptedProviders() throws IOException {
+ Properties props = new Properties();
+ try (InputStream is = getClass().getClassLoader()
+ .getResourceAsStream(PROVIDER_INVENTORY)) {
+ if (is != null) {
+ props.load(is);
+ }
+ }
+ List<String> accepted = new ArrayList<>();
+ for (String key : props.stringPropertyNames()) {
+ if (key.startsWith("provider.")
+ && "ACCEPTED".equals(props.getProperty(key).trim())) {
+ accepted.add(key.substring("provider.".length()));
+ }
+ }
+ return accepted;
}
private static boolean hasSetter(Class<?> configClass, Field field) {
diff --git
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ImmigrationScopeTest.java
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ImmigrationScopeTest.java
new file mode 100644
index 0000000..20f37fd
--- /dev/null
+++
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ImmigrationScopeTest.java
@@ -0,0 +1,259 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.server.graalvm;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Immigration scope detector — catches new upstream providers and rule files
+ * after {@code skywalking/} submodule updates.
+ *
+ * <p>Scans the upstream source tree for ModuleProvider implementations and
+ * OAL/MAL/LAL rule files, comparing them against explicit inventories. Any
+ * unrecognized addition causes a test failure, forcing the developer to
+ * categorize new providers (ACCEPTED/NOT_ACCEPTED) and add new rule files
+ * to the precompiler.
+ */
+class ImmigrationScopeTest {
+
+ private static final String PROVIDER_INVENTORY =
"provider-inventory.properties";
+ private static final String RULE_FILE_INVENTORY =
"rule-file-inventory.properties";
+
+ /**
+ * Patterns that indicate a class is a ModuleProvider implementation.
+ * Covers direct subclasses and {@code AbstractConfigurationProvider}
+ * subclasses. Sub-providers that extend other tracked providers
+ * (e.g. MySQL/PostgreSQL extending JDBCStorageProvider) are not
+ * scanned separately — the parent provider entry covers them.
+ */
+ private static final Pattern EXTENDS_PROVIDER = Pattern.compile(
+ "\\bextends\\s+(ModuleProvider|AbstractConfigurationProvider)\\b"
+ );
+
+ // ─── Provider inventory ─────────────────────────────────────────────
+
+ @Test
+ void allUpstreamProvidersAreCategorized() throws Exception {
+ Path projectRoot = Path.of(System.getProperty("user.dir")).getParent();
+ Path oapServer = projectRoot.resolve("skywalking/oap-server");
+ assertTrue(Files.isDirectory(oapServer),
+ "skywalking/oap-server not found — is the submodule initialized?");
+
+ // Scan upstream for provider implementations
+ Set<String> upstreamProviders = scanProviders(oapServer);
+
+ // Load inventory
+ Properties inventory = loadProperties(PROVIDER_INVENTORY);
+ Set<String> inventoryProviders = new HashSet<>();
+ for (String key : inventory.stringPropertyNames()) {
+ if (key.startsWith("provider.")) {
+ inventoryProviders.add(key.substring("provider.".length()));
+ }
+ }
+
+ // Find providers in upstream but not in inventory
+ Set<String> unknown = new TreeSet<>(upstreamProviders);
+ unknown.removeAll(inventoryProviders);
+
+ // Find providers in inventory but not in upstream (stale entries)
+ Set<String> stale = new TreeSet<>(inventoryProviders);
+ stale.removeAll(upstreamProviders);
+
+ StringBuilder msg = new StringBuilder();
+ if (!unknown.isEmpty()) {
+ msg.append("New upstream providers not in inventory — add as
ACCEPTED or NOT_ACCEPTED:\n");
+ for (String fqcn : unknown) {
+ msg.append(" provider.").append(fqcn).append(" = ???\n");
+ }
+ }
+ if (!stale.isEmpty()) {
+ msg.append("Providers in inventory but not found upstream
(removed?):\n");
+ for (String fqcn : stale) {
+ msg.append(" provider.").append(fqcn).append('\n');
+ }
+ }
+
+ if (msg.length() > 0) {
+ fail(msg.toString());
+ }
+ }
+
+ /**
+ * Scans all {@code src/main/java/} directories under oap-server for
classes
+ * that extend {@code ModuleProvider} or {@code
AbstractConfigurationProvider}.
+ * Excludes Mock* classes (test tools) and ignores {@code target/}
directories.
+ */
+ private Set<String> scanProviders(Path oapServer) throws IOException {
+ Set<String> providers = new HashSet<>();
+
+ Files.walkFileTree(oapServer, new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) {
+ String name = dir.getFileName().toString();
+ // Skip target/ and test/ directories
+ if ("target".equals(name) || "test".equals(name)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes
attrs)
+ throws IOException {
+ if (!file.toString().endsWith(".java")) {
+ return FileVisitResult.CONTINUE;
+ }
+ // Only scan src/main/java files
+ if (!file.toString().contains("/src/main/java/")) {
+ return FileVisitResult.CONTINUE;
+ }
+ String className = file.getFileName().toString()
+ .replace(".java", "");
+ // Skip Mock* classes (test tools)
+ if (className.startsWith("Mock")) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ // Check if file contains extends ModuleProvider or
+ // extends AbstractConfigurationProvider
+ boolean isProvider = false;
+ String packageName = null;
+ try (BufferedReader reader = Files.newBufferedReader(file)) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (packageName == null && line.startsWith("package
")) {
+ packageName = line.replace("package ", "")
+ .replace(";", "").trim();
+ }
+ if (EXTENDS_PROVIDER.matcher(line).find()) {
+ isProvider = true;
+ }
+ if (packageName != null && isProvider) {
+ break;
+ }
+ }
+ }
+
+ if (isProvider && packageName != null) {
+ providers.add(packageName + "." + className);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ return providers;
+ }
+
+ // ─── Rule file inventory ────────────────────────────────────────────
+
+ @Test
+ void allUpstreamRuleFilesAreTracked() throws Exception {
+ Path projectRoot = Path.of(System.getProperty("user.dir")).getParent();
+ Path resources = projectRoot.resolve(
+ "skywalking/oap-server/server-starter/src/main/resources");
+ assertTrue(Files.isDirectory(resources),
+ "server-starter resources not found — is the submodule
initialized?");
+
+ // Scan upstream rule files
+ Set<String> upstreamFiles = new TreeSet<>();
+ String[] ruleDirectories = {
+ "oal", "meter-analyzer-config", "otel-rules",
+ "log-mal-rules", "lal", "envoy-metrics-rules",
+ "telegraf-rules", "zabbix-rules"
+ };
+ for (String dir : ruleDirectories) {
+ Path ruleDir = resources.resolve(dir);
+ if (!Files.isDirectory(ruleDir)) {
+ continue;
+ }
+ Files.walkFileTree(ruleDir, new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) {
+ String name = file.getFileName().toString();
+ if (name.endsWith(".oal") || name.endsWith(".yaml")) {
+ upstreamFiles.add(
+ resources.relativize(file).toString());
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ // Load inventory
+ Properties inventory = loadProperties(RULE_FILE_INVENTORY);
+ Set<String> inventoryFiles = new TreeSet<>();
+ for (String key : inventory.stringPropertyNames()) {
+ inventoryFiles.add(key.trim());
+ }
+
+ // Find files in upstream but not in inventory
+ Set<String> unknown = new TreeSet<>(upstreamFiles);
+ unknown.removeAll(inventoryFiles);
+
+ // Find files in inventory but not in upstream (removed?)
+ Set<String> stale = new TreeSet<>(inventoryFiles);
+ stale.removeAll(upstreamFiles);
+
+ StringBuilder msg = new StringBuilder();
+ if (!unknown.isEmpty()) {
+ msg.append("New upstream rule files not in inventory — add to
precompiler and inventory:\n");
+ for (String f : unknown) {
+ msg.append(" ").append(f).append(" = ACCEPTED\n");
+ }
+ }
+ if (!stale.isEmpty()) {
+ msg.append("Rule files in inventory but not found upstream
(removed?):\n");
+ for (String f : stale) {
+ msg.append(" ").append(f).append('\n');
+ }
+ }
+
+ if (msg.length() > 0) {
+ fail(msg.toString());
+ }
+ }
+
+ // ─── Helpers ────────────────────────────────────────────────────────
+
+ private Properties loadProperties(String resource) throws IOException {
+ Properties props = new Properties();
+ try (InputStream is = getClass().getClassLoader()
+ .getResourceAsStream(resource)) {
+ if (is != null) {
+ props.load(is);
+ }
+ }
+ return props;
+ }
+}
diff --git
a/oap-graalvm-server/src/test/resources/provider-inventory.properties
b/oap-graalvm-server/src/test/resources/provider-inventory.properties
new file mode 100644
index 0000000..0ceeca6
--- /dev/null
+++ b/oap-graalvm-server/src/test/resources/provider-inventory.properties
@@ -0,0 +1,108 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Module provider inventory — immigration scope detector
+# Tracks all upstream ModuleProvider implementations and their acceptance
status.
+# When a new provider appears upstream (e.g. after skywalking/ submodule
update),
+# ImmigrationScopeTest fails, forcing explicit categorization.
+#
+# Format: provider.FQCN = ACCEPTED | NOT_ACCEPTED
+# ACCEPTED: wired in GraalVMOAPServerStartUp, config covered
+# NOT_ACCEPTED: explicitly excluded from this distro
+
+# --- Core ---
+provider.org.apache.skywalking.oap.server.core.CoreModuleProvider = ACCEPTED
+
+# --- Cluster ---
+provider.org.apache.skywalking.oap.server.cluster.plugin.standalone.ClusterModuleStandaloneProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.cluster.plugin.kubernetes.ClusterModuleKubernetesProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.cluster.plugin.consul.ClusterModuleConsulProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.cluster.plugin.etcd.ClusterModuleEtcdProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.cluster.plugin.nacos.ClusterModuleNacosProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.cluster.plugin.zookeeper.ClusterModuleZookeeperProvider
= NOT_ACCEPTED
+
+# --- Storage ---
+provider.org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.storage.plugin.elasticsearch.StorageModuleElasticsearchProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCStorageProvider
= NOT_ACCEPTED
+
+# --- Configuration ---
+provider.org.apache.skywalking.oap.server.configuration.configmap.ConfigmapConfigurationProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.api.NoneConfigurationProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.api.AbstractConfigurationProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.apollo.ApolloConfigurationProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.consul.ConsulConfigurationProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.etcd.EtcdConfigurationProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.nacos.NacosConfigurationProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.zookeeper.ZookeeperConfigurationProvider
= NOT_ACCEPTED
+provider.org.apache.skywalking.oap.server.configuration.grpc.GRPCConfigurationProvider
= NOT_ACCEPTED
+
+# --- Telemetry ---
+provider.org.apache.skywalking.oap.server.telemetry.prometheus.PrometheusTelemetryProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.telemetry.none.NoneTelemetryProvider
= NOT_ACCEPTED
+
+# --- Analyzers ---
+provider.org.apache.skywalking.oap.server.analyzer.provider.AnalyzerModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.log.analyzer.provider.LogAnalyzerModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.analyzer.event.EventAnalyzerModuleProvider
= ACCEPTED
+
+# --- Receivers ---
+provider.org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.register.provider.RegisterModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.trace.provider.TraceModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.jvm.provider.JVMModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.clr.provider.CLRModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.profile.provider.ProfileModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.asyncprofiler.provider.AsyncProfilerModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.pprof.provider.PprofModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.zabbix.provider.ZabbixReceiverProvider
= ACCEPTED
+provider.org.apache.skywalking.aop.server.receiver.mesh.MeshReceiverProvider =
ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.envoy.EnvoyMetricReceiverProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.meter.provider.MeterReceiverProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.otel.OtelMetricReceiverProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.zipkin.ZipkinReceiverProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.browser.provider.BrowserModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.log.provider.LogModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.event.EventModuleProvider =
ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.ebpf.provider.EBPFReceiverProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.telegraf.provider.TelegrafReceiverProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.aws.firehose.AWSFirehoseReceiverModuleProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.receiver.configuration.discovery.ConfigurationDiscoveryProvider
= ACCEPTED
+
+# --- Fetchers ---
+provider.org.apache.skywalking.oap.server.analyzer.agent.kafka.provider.KafkaFetcherProvider
= ACCEPTED
+provider.org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherProvider
= ACCEPTED
+
+# --- Query ---
+provider.org.apache.skywalking.oap.query.graphql.GraphQLQueryProvider =
ACCEPTED
+provider.org.apache.skywalking.oap.query.zipkin.ZipkinQueryProvider = ACCEPTED
+provider.org.apache.skywalking.oap.query.promql.PromQLProvider = ACCEPTED
+provider.org.apache.skywalking.oap.query.logql.LogQLProvider = ACCEPTED
+provider.org.apache.skywalking.oap.query.debug.StatusQueryProvider = ACCEPTED
+
+# --- Alarm ---
+provider.org.apache.skywalking.oap.server.core.alarm.provider.AlarmModuleProvider
= ACCEPTED
+
+# --- Exporter ---
+provider.org.apache.skywalking.oap.server.exporter.provider.ExporterProvider =
ACCEPTED
+
+# --- Health Checker ---
+provider.org.apache.skywalking.oap.server.health.checker.provider.HealthCheckerProvider
= ACCEPTED
+
+# --- AI Pipeline ---
+provider.org.apache.skywalking.oap.server.ai.pipeline.AIPipelineProvider =
ACCEPTED
+
+# --- Tools (not production) ---
+provider.org.apache.skywalking.module.DataGeneratorModuleProvider =
NOT_ACCEPTED
diff --git
a/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
index 77f02a3..17cee20 100644
--- a/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
+++ b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
@@ -22,10 +22,68 @@
# Format: relative/path/to/upstream/Source.java = sha256hex
# To update: shasum -a 256 <path>
-# Module system replacement (direct provider wiring without ServiceLoader)
-skywalking/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleDefine.java
= 89add3015c4265f50a13a9e5800d68aaa43e73f50c1224343712d2744b6e2437
+# --- server-core-for-graalvm ---
+# OAL manifest loader (replaces Javassist runtime generation)
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/oal/rt/OALEngineLoaderService.java
= 32c4554a851e4faa93f87a8278e3d869139cb4188edf8026d7556ea7b9bce93c
+# Annotation manifest loader (replaces Guava ClassPath scan)
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/annotation/AnnotationScan.java
= 06fc9cbedca66ad0d79ef1bd08bcb58113e6cfabb629098815c649b9f56ec9a5
+# Dispatcher manifest loader (replaces Guava ClassPath scan)
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/SourceReceiverImpl.java
= 3f0ad755a6d02666ad468c9d8c65fcc02d490507b59dfb6235fe2a5b9a070a20
+# MeterFunction manifest loader (replaces Guava ClassPath scan + Javassist)
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem.java
= fea99b625841e20e0fc5c13f43dd19ce8939ceac546a4bbc805592bca5e3961d
+# Added @Setter at class level
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleConfig.java
= f17b294a952670c00ef0b26059cc7fdf458ced0861c5c00210594ba4953edf30
+# Java-backed closures instead of GroovyShell
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
= ffadc2cb0a3cfe85b53b3d7fbd74505c7e528f187fd6dc615ede523642bb6c26
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
= 600eaa0c5f5d873792997ece22fb4560e422b987d374d0ea0667e855b4f28d96
-# Config loader replacements (load from JSON manifests instead of filesystem
YAML)
-skywalking/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.java
= 979b1d081a7e0aa1b627a525157d9f024f81a3db289e76284c54dbf508c494b1
+# --- meter-analyzer-for-graalvm ---
+# MAL DSL: loads transpiled MalExpression from manifest
+skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/DSL.java
= 06f5ad274b9b237be37d22cde017246b944331711651c012fa6addae097061ad
+# MAL filter: loads transpiled MalFilter from manifest
+skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/FilterExpression.java
= a17742a5bcb42f2328a9a32b61dea92e314916f85bd52cd5b88be530f640b33f
+# MAL expression: uses MalExpression instead of DelegatingScript
+skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/Expression.java
= 794c977fc90d1ff4c217d87477df198971b02fe78659167bbe207a1e36ef6d57
+skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/ExpressionParsingContext.java
= d172ac8d0209566932a144f269d474c0b5c23eb83500e8c8e5ce08eed7c57170
+# Closure params -> Java functional interfaces
+skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/SampleFamily.java
= b2cbe3636f5ba083caa41b92ab3c11188a33fc38dbc47378d795c0859bfbeb74
+skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/EntityDescription/InstanceEntityDescription.java
= 4e7a7f9b17a74e886d24de6953476cb3e8001e48ae3ad8287efe00c9d92140df
+# Config loader: load from JSON manifests instead of filesystem YAML
skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/prometheus/rule/Rules.java
= 1f300c978e9dca2464379463b40544d8114500b1f87d2df10005c518dd71db99
+
+# --- log-analyzer-for-graalvm ---
+# LAL DSL: loads transpiled LalExpression from manifest
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/DSL.java
= b74995751450131dd73921199b4247cee040f3e3d26fd32035dc6f7e029f087b
+# Added @Setter at class level
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/provider/LogAnalyzerModuleConfig.java
= 265d603c1c523d99d028bd5f9f1db783ef4e5b16884ca9bed1e8e8c67321168e
+# Config loader: load from JSON manifests instead of filesystem YAML
skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/provider/LALConfigs.java
= ecb7ddbc94bd4073e885e76c472dddd171e9b11155402faabb33923b55e38eee
+# Spec classes: added Consumer overloads for transpiled code
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/spec/AbstractSpec.java
= 4ba0ded4649dcf97ad96f1063332bcd350ccff3fa2573abaa6f6c6610cbeaec8
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/spec/filter/FilterSpec.java
= 9f8dcb3b306af65913d069dd0cead96c6c9bb4c06f18439d5b440f7f51ef8b49
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/spec/extractor/ExtractorSpec.java
= f4c8ae01e6f312febe42324913befb2d4b1782657ed69e5359a768ef8b3732da
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/spec/sink/SinkSpec.java
= bf1d9082948bdb0205529cbda87d8850f5adbe1af77e6ca352290197709e5628
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/spec/sink/SamplerSpec.java
= 6c5b8ba5a3d3c82c9e415bc131b39cbb8bcb25e0cc99a8a5f12137ec8666fcac
+
+# --- agent-analyzer-for-graalvm ---
+# Added @Setter at class level
+skywalking/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/AnalyzerModuleConfig.java
= b9de4e402475213251d32f9385a07c41d445225f2b7a9c2d4b9c402084b1a544
+# Config loader: load from JSON manifests instead of filesystem YAML
+skywalking/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.java
= 979b1d081a7e0aa1b627a525157d9f024f81a3db289e76284c54dbf508c494b1
+
+# --- library-module-for-graalvm ---
+# Direct provider wiring without ServiceLoader
+skywalking/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleDefine.java
= 89add3015c4265f50a13a9e5800d68aaa43e73f50c1224343712d2744b6e2437
+
+# --- library-util-for-graalvm ---
+# Config loading: type-dispatch with Lombok setters instead of reflection
+skywalking/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
= 041a64c32e0296cc799e12d192d4f15bdec83ac5660cc01dc00fd57734a64768
+
+# --- Config-only replacements (added @Setter at class level) ---
+skywalking/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverConfig.java
= 2113f0e0c214ec002ba94d8dd06d1ba929c7f54f111266982d1da77c6574c485
+skywalking/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/OtelMetricReceiverConfig.java
= eb7e97efc9dc19bbeb2511798c0869ca1aad8ddf020c599d0ce975a70ca7ef14
+skywalking/oap-server/server-receiver-plugin/skywalking-ebpf-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/ebpf/provider/EBPFReceiverModuleConfig.java
= 2318e388dab8205280b25d92c1ec4271caf2ba2966c1791a309c800935afaf34
+skywalking/oap-server/server-receiver-plugin/aws-firehose-receiver/src/main/java/org/apache/skywalking/oap/server/receiver/aws/firehose/AWSFirehoseReceiverModuleConfig.java
= aef19babbeece9dbd90131e23699768c0f336b354dff75a7bd7b7b2fb8add592
+skywalking/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherConfig.java
= f1872663b062cb6832cdc1abdcf1030175e98ecc363c5208cd045058da53bc53
+skywalking/oap-server/server-query-plugin/status-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/StatusQueryConfig.java
= 1aa61fd4b7704481f2f4c9c36947e8388e546625aefd2fd3defc65282af9dce7
+skywalking/oap-server/server-health-checker/src/main/java/org/apache/skywalking/oap/server/health/checker/provider/HealthCheckerConfig.java
= 76ddf18b1b59584e3ff406545c03e6772a25d2bea316248b72f38ba2c8f61f15
diff --git
a/oap-graalvm-server/src/test/resources/rule-file-inventory.properties
b/oap-graalvm-server/src/test/resources/rule-file-inventory.properties
new file mode 100644
index 0000000..6ac2ad5
--- /dev/null
+++ b/oap-graalvm-server/src/test/resources/rule-file-inventory.properties
@@ -0,0 +1,127 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Rule file inventory — immigration scope detector
+# Tracks all OAL/MAL/LAL rule files in upstream. When a new file appears
+# (e.g. after skywalking/ submodule update), ImmigrationScopeTest fails,
+# forcing it to be added to the precompiler and this inventory.
+#
+# Format: relative/path = ACCEPTED
+# All rule files should be ACCEPTED (added to precompiler).
+
+# --- OAL scripts (9 files) ---
+oal/browser.oal = ACCEPTED
+oal/cilium.oal = ACCEPTED
+oal/core.oal = ACCEPTED
+oal/disable.oal = ACCEPTED
+oal/dotnet-agent.oal = ACCEPTED
+oal/ebpf.oal = ACCEPTED
+oal/java-agent.oal = ACCEPTED
+oal/mesh.oal = ACCEPTED
+oal/tcp.oal = ACCEPTED
+
+# --- meter-analyzer-config (11 files) ---
+meter-analyzer-config/continuous-profiling.yaml = ACCEPTED
+meter-analyzer-config/datasource.yaml = ACCEPTED
+meter-analyzer-config/go-agent.yaml = ACCEPTED
+meter-analyzer-config/go-runtime.yaml = ACCEPTED
+meter-analyzer-config/java-agent.yaml = ACCEPTED
+meter-analyzer-config/network-profiling.yaml = ACCEPTED
+meter-analyzer-config/python-runtime.yaml = ACCEPTED
+meter-analyzer-config/ruby-runtime.yaml = ACCEPTED
+meter-analyzer-config/satellite.yaml = ACCEPTED
+meter-analyzer-config/spring-micrometer.yaml = ACCEPTED
+meter-analyzer-config/threadpool.yaml = ACCEPTED
+
+# --- otel-rules (49 files) ---
+otel-rules/activemq/activemq-broker.yaml = ACCEPTED
+otel-rules/activemq/activemq-cluster.yaml = ACCEPTED
+otel-rules/activemq/activemq-destination.yaml = ACCEPTED
+otel-rules/apisix.yaml = ACCEPTED
+otel-rules/aws-dynamodb/dynamodb-endpoint.yaml = ACCEPTED
+otel-rules/aws-dynamodb/dynamodb-service.yaml = ACCEPTED
+otel-rules/aws-eks/eks-cluster.yaml = ACCEPTED
+otel-rules/aws-eks/eks-node.yaml = ACCEPTED
+otel-rules/aws-eks/eks-service.yaml = ACCEPTED
+otel-rules/aws-gateway/gateway-endpoint.yaml = ACCEPTED
+otel-rules/aws-gateway/gateway-service.yaml = ACCEPTED
+otel-rules/aws-s3/s3-service.yaml = ACCEPTED
+otel-rules/banyandb/banyandb-instance.yaml = ACCEPTED
+otel-rules/banyandb/banyandb-service.yaml = ACCEPTED
+otel-rules/bookkeeper/bookkeeper-cluster.yaml = ACCEPTED
+otel-rules/bookkeeper/bookkeeper-node.yaml = ACCEPTED
+otel-rules/clickhouse/clickhouse-instance.yaml = ACCEPTED
+otel-rules/clickhouse/clickhouse-service.yaml = ACCEPTED
+otel-rules/elasticsearch/elasticsearch-cluster.yaml = ACCEPTED
+otel-rules/elasticsearch/elasticsearch-index.yaml = ACCEPTED
+otel-rules/elasticsearch/elasticsearch-node.yaml = ACCEPTED
+otel-rules/flink/flink-job.yaml = ACCEPTED
+otel-rules/flink/flink-jobManager.yaml = ACCEPTED
+otel-rules/flink/flink-taskManager.yaml = ACCEPTED
+otel-rules/istio-controlplane.yaml = ACCEPTED
+otel-rules/k8s/k8s-cluster.yaml = ACCEPTED
+otel-rules/k8s/k8s-instance.yaml = ACCEPTED
+otel-rules/k8s/k8s-node.yaml = ACCEPTED
+otel-rules/k8s/k8s-service.yaml = ACCEPTED
+otel-rules/kafka/kafka-broker.yaml = ACCEPTED
+otel-rules/kafka/kafka-cluster.yaml = ACCEPTED
+otel-rules/kong/kong-endpoint.yaml = ACCEPTED
+otel-rules/kong/kong-instance.yaml = ACCEPTED
+otel-rules/kong/kong-service.yaml = ACCEPTED
+otel-rules/mongodb/mongodb-cluster.yaml = ACCEPTED
+otel-rules/mongodb/mongodb-node.yaml = ACCEPTED
+otel-rules/mysql/mysql-instance.yaml = ACCEPTED
+otel-rules/mysql/mysql-service.yaml = ACCEPTED
+otel-rules/nginx/nginx-endpoint.yaml = ACCEPTED
+otel-rules/nginx/nginx-instance.yaml = ACCEPTED
+otel-rules/nginx/nginx-service.yaml = ACCEPTED
+otel-rules/oap.yaml = ACCEPTED
+otel-rules/postgresql/postgresql-instance.yaml = ACCEPTED
+otel-rules/postgresql/postgresql-service.yaml = ACCEPTED
+otel-rules/pulsar/pulsar-broker.yaml = ACCEPTED
+otel-rules/pulsar/pulsar-cluster.yaml = ACCEPTED
+otel-rules/rabbitmq/rabbitmq-cluster.yaml = ACCEPTED
+otel-rules/rabbitmq/rabbitmq-node.yaml = ACCEPTED
+otel-rules/redis/redis-instance.yaml = ACCEPTED
+otel-rules/redis/redis-service.yaml = ACCEPTED
+otel-rules/rocketmq/rocketmq-broker.yaml = ACCEPTED
+otel-rules/rocketmq/rocketmq-cluster.yaml = ACCEPTED
+otel-rules/rocketmq/rocketmq-topic.yaml = ACCEPTED
+otel-rules/vm.yaml = ACCEPTED
+otel-rules/windows.yaml = ACCEPTED
+
+# --- log-mal-rules (2 files) ---
+log-mal-rules/nginx.yaml = ACCEPTED
+log-mal-rules/placeholder.yaml = ACCEPTED
+
+# --- envoy-metrics-rules (2 files) ---
+envoy-metrics-rules/envoy.yaml = ACCEPTED
+envoy-metrics-rules/envoy-svc-relation.yaml = ACCEPTED
+
+# --- telegraf-rules (1 file) ---
+telegraf-rules/vm.yaml = ACCEPTED
+
+# --- zabbix-rules (1 file) ---
+zabbix-rules/agent.yaml = ACCEPTED
+
+# --- LAL (8 files) ---
+lal/default.yaml = ACCEPTED
+lal/envoy-als.yaml = ACCEPTED
+lal/k8s-service.yaml = ACCEPTED
+lal/mesh-dp.yaml = ACCEPTED
+lal/mysql-slowsql.yaml = ACCEPTED
+lal/nginx.yaml = ACCEPTED
+lal/pgsql-slowsql.yaml = ACCEPTED
+lal/redis-slowsql.yaml = ACCEPTED
diff --git a/oap-libs-for-graalvm/CLAUDE.md b/oap-libs-for-graalvm/CLAUDE.md
new file mode 100644
index 0000000..b49bbc7
--- /dev/null
+++ b/oap-libs-for-graalvm/CLAUDE.md
@@ -0,0 +1,164 @@
+# oap-libs-for-graalvm — Same-FQCN Replacement Modules
+
+## Purpose
+
+Each module under `oap-libs-for-graalvm/` repackages one upstream SkyWalking
JAR
+using `maven-shade-plugin`. The shade plugin includes the full upstream JAR but
+**excludes** specific `.class` files, replacing them with GraalVM-compatible
+versions that live in this module's `src/main/java/`.
+
+## Sync with Upstream (`skywalking/` submodule)
+
+Every replacement class must stay in sync with its upstream counterpart. When
the
+`skywalking/` submodule is updated, replacement classes may need corresponding
updates.
+
+### Staleness Detection
+
+Two test-based mechanisms detect upstream drift:
+
+1. **`ReplacementClassStalenessTest`** — SHA-256 tracks upstream `.java`
source files.
+ Hashes recorded in
`oap-graalvm-server/src/test/resources/replacement-source-sha256.properties`.
+ Currently tracks 4 files (see "Tracking Gaps" below).
+
+2. **`PrecompiledYamlStalenessTest`** — SHA-256 tracks ~49 YAML rule files
consumed
+ by the precompiler. Hashes recorded in
`oap-graalvm-server/src/test/resources/precompiled-yaml-sha256.properties`.
+
+### After a submodule update
+
+```bash
+# 1. Run staleness tests
+JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal \
+ mvn -pl oap-graalvm-server test \
+ -Dtest="ReplacementClassStalenessTest,PrecompiledYamlStalenessTest"
+
+# 2. If tests fail, review changed upstream files and update replacements
+# 3. Update SHA-256 hashes:
+shasum -a 256 skywalking/oap-server/path/to/changed/Source.java
+
+# 4. Full build to verify
+JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal make build-distro
+```
+
+## Complete Replacement Inventory
+
+### server-core-for-graalvm (7 classes)
+
+| Replacement Class | Upstream Source | Change | Staleness Tracked |
+|---|---|---|---|
+| `OALEngineLoaderService` |
`server-core/.../oal/rt/OALEngineLoaderService.java` | Load OAL classes from
manifests instead of Javassist | No |
+| `AnnotationScan` | `server-core/.../annotation/AnnotationScan.java` | Read
manifests instead of Guava ClassPath scan | No |
+| `SourceReceiverImpl` | `server-core/.../source/SourceReceiverImpl.java` |
Read manifests instead of Guava ClassPath scan | No |
+| `MeterSystem` | `server-core/.../analysis/meter/MeterSystem.java` | Read
MeterFunction manifest; load pre-generated Javassist classes | No |
+| `CoreModuleConfig` | `server-core/.../CoreModuleConfig.java` | Added
`@Setter` at class level | No |
+| `HierarchyDefinitionService` |
`server-core/.../config/HierarchyDefinitionService.java` | Java-backed closures
instead of GroovyShell | No |
+| `HierarchyService` | `server-core/.../hierarchy/HierarchyService.java` |
Support for Java-backed closures | No |
+
+### meter-analyzer-for-graalvm (10 classes)
+
+| Replacement Class | Upstream Source | Change | Staleness Tracked |
+|---|---|---|---|
+| `DSL` | `meter-analyzer/.../dsl/DSL.java` | Load transpiled `MalExpression`
from manifest | No |
+| `FilterExpression` | `meter-analyzer/.../dsl/FilterExpression.java` | Load
transpiled `MalFilter` from manifest | No |
+| `Expression` | `meter-analyzer/.../dsl/Expression.java` | Uses
`MalExpression` instead of `DelegatingScript` | No |
+| `ExpressionParsingContext` |
`meter-analyzer/.../dsl/ExpressionParsingContext.java` | Adapted for
`MalExpression` | No |
+| `SampleFamily` | `meter-analyzer/.../dsl/SampleFamily.java` | Closure params
→ Java functional interfaces | No |
+| `InstanceEntityDescription` |
`meter-analyzer/.../EntityDescription/InstanceEntityDescription.java` | Closure
params → Java functional interfaces | No |
+| `Rules` | `meter-analyzer/.../prometheus/rule/Rules.java` | Load from JSON
manifests instead of filesystem YAML | **Yes** |
+| `MalExpression` | (new) | Interface for transpiled MAL expressions | N/A |
+| `MalFilter` | (new) | Interface for transpiled MAL filters | N/A |
+| `SampleFamilyFunctions` | (new) | Java functional interfaces replacing
Groovy Closures | N/A |
+
+### log-analyzer-for-graalvm (9 classes)
+
+| Replacement Class | Upstream Source | Change | Staleness Tracked |
+|---|---|---|---|
+| `DSL` | `log-analyzer/.../dsl/DSL.java` | Load transpiled `LalExpression`
from manifest | No |
+| `LogAnalyzerModuleConfig` |
`log-analyzer/.../provider/LogAnalyzerModuleConfig.java` | Added `@Setter` at
class level | No |
+| `LALConfigs` | `log-analyzer/.../provider/LALConfigs.java` | Load from JSON
manifests instead of filesystem YAML | **Yes** |
+| `AbstractSpec` | `log-analyzer/.../dsl/spec/AbstractSpec.java` | Added
`abort()` no-arg overload | No |
+| `FilterSpec` | `log-analyzer/.../dsl/spec/filter/FilterSpec.java` | Added
`Consumer` overloads for transpiled code | No |
+| `ExtractorSpec` | `log-analyzer/.../dsl/spec/extractor/ExtractorSpec.java` |
Added `Consumer` overloads | No |
+| `SinkSpec` | `log-analyzer/.../dsl/spec/sink/SinkSpec.java` | Added
`Consumer` overloads | No |
+| `SamplerSpec` | `log-analyzer/.../dsl/spec/sink/SamplerSpec.java` | Added
String-keyed sampler overloads | No |
+| `LalExpression` | (new) | Interface for transpiled LAL expressions | N/A |
+
+### agent-analyzer-for-graalvm (2 classes)
+
+| Replacement Class | Upstream Source | Change | Staleness Tracked |
+|---|---|---|---|
+| `AnalyzerModuleConfig` |
`agent-analyzer/.../provider/AnalyzerModuleConfig.java` | Added `@Setter` at
class level | No |
+| `MeterConfigs` | `agent-analyzer/.../meter/config/MeterConfigs.java` | Load
from JSON manifests instead of filesystem YAML | **Yes** |
+
+### library-module-for-graalvm (1 class)
+
+| Replacement Class | Upstream Source | Change | Staleness Tracked |
+|---|---|---|---|
+| `ModuleDefine` | `library-module/.../module/ModuleDefine.java` | Added
`prepare()` overload for direct provider wiring | **Yes** |
+
+### library-util-for-graalvm (0 classes, shade-only)
+
+No replacement Java sources. Uses shade plugin to exclude
`YamlConfigLoaderUtils`,
+`ResourceUtils`, `FieldsHelper` from upstream JAR. The replacements for these
live
+in `oap-graalvm-server/` (due to 30+ cross-module imports).
+
+### Config-only replacements (added `@Setter` at class level)
+
+| Module | Replacement Class | Staleness Tracked |
+|---|---|---|
+| `envoy-metrics-receiver-for-graalvm` | `EnvoyMetricReceiverConfig` | No |
+| `otel-receiver-for-graalvm` | `OtelMetricReceiverConfig` | No |
+| `ebpf-receiver-for-graalvm` | `EBPFReceiverModuleConfig` | No |
+| `aws-firehose-receiver-for-graalvm` | `AWSFirehoseReceiverModuleConfig` | No
|
+| `cilium-fetcher-for-graalvm` | `CiliumFetcherConfig` | No |
+| `status-query-for-graalvm` | `StatusQueryConfig` | No |
+| `health-checker-for-graalvm` | `HealthCheckerConfig` | No |
+
+### groovy-stubs (12 stub classes)
+
+Minimal `groovy.lang.*` stubs for class loading. No `org.codehaus.groovy.*`
packages
+(prevents GraalVM `GroovyIndyInterfaceFeature` from activating). Not a
replacement
+of any upstream class — no staleness tracking needed.
+
+### server-starter-for-graalvm (0 classes, resource-only)
+
+Repackages upstream `server-starter` with `version.properties` excluded (distro
+generates its own from git).
+
+## Tracking Gaps
+
+Only **4 of ~37 replacement source files** are tracked in
`replacement-source-sha256.properties`:
+
+- `ModuleDefine.java`
+- `MeterConfigs.java`
+- `Rules.java`
+- `LALConfigs.java`
+
+The following categories of upstream files have **no SHA-256 staleness
tracking**:
+
+| Category | Count | Risk |
+|---|---|---|
+| Non-trivial rewrites (OALEngineLoaderService, AnnotationScan,
SourceReceiverImpl, MeterSystem, DSL x2, FilterExpression, Expression,
SampleFamily, HierarchyDefinitionService) | ~10 | **High** — upstream API
changes would silently break |
+| `@Setter` additions (CoreModuleConfig, AnalyzerModuleConfig,
LogAnalyzerModuleConfig, 7 config classes) | ~10 | **Medium** — new fields
added upstream won't get setters |
+| Spec class `Consumer` overloads (AbstractSpec, FilterSpec, ExtractorSpec,
SinkSpec, SamplerSpec) | 5 | **Medium** — new DSL methods upstream won't get
overloads |
+
+## Verification Tests
+
+All tests live in `oap-graalvm-server/src/test/`:
+
+| Test | What It Verifies |
+|---|---|
+| `ReplacementClassStalenessTest` | SHA-256 of 4 tracked upstream sources |
+| `PrecompiledYamlStalenessTest` | SHA-256 of ~49 YAML rule files |
+| `PrecompiledRegistrationTest` | Manifests match live Guava ClassPath scans;
all OAL/MAL/LAL classes loadable |
+| 73 MAL comparison tests | Dual-path: fresh Groovy vs transpiled Java (1281
assertions) |
+| 5 LAL comparison tests | Dual-path: fresh Groovy vs transpiled Java (19
assertions) |
+
+## Adding a New Replacement
+
+1. Create (or add to existing) `*-for-graalvm` module under
`oap-libs-for-graalvm/`
+2. Add the replacement `.java` file with the **same FQCN** as upstream
+3. Configure shade plugin in `pom.xml` to exclude the original `.class` (and
inner classes with `$*`)
+4. Add the `-for-graalvm` artifact to root `pom.xml` `<dependencyManagement>`
+5. In `oap-graalvm-server/pom.xml`: add original JAR to
`<dependencyManagement>` as `provided`, add `-for-graalvm` to `<dependencies>`
+6. Add the original JAR to `distribution.xml` `<excludes>`
+7. Add upstream source SHA-256 to `replacement-source-sha256.properties`