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`

Reply via email to