srcmorph-maven-plugin
Used in:
components
- OverviewOverview
- VersionsVersions
- DependentsDependents
- DependenciesDependencies
<dependency>
<groupId>net.ladenthin</groupId>
<artifactId>srcmorph-maven-plugin</artifactId>
<version>1.1.1</version>
</dependency><!--
SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
SPDX-License-Identifier: Apache-2.0
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.ladenthin</groupId>
<artifactId>srcmorph-parent</artifactId>
<version>1.1.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>srcmorph-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>srcmorph-maven-plugin</name>
<description>Free Maven plugin for hierarchical AI-readable indexing and summarization of source code projects using llama.cpp-compatible local models. Formerly published as net.ladenthin:llamacpp-ai-index-maven-plugin (see the relocation stub of that name).</description>
<properties>
<sonar.organization>bernardladenthin</sonar.organization>
<maven.compiler.release>8</maven.compiler.release>
<maven.compiler.testRelease>21</maven.compiler.testRelease>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.plugin.tools.version>3.15.2</maven.plugin.tools.version>
<maven.version>3.9.16</maven.version>
<!-- net.ladenthin:llama is now a dependency of the srcmorph core module (only the
provider package touches it); this module no longer declares it directly. The
gpu-cuda / gpu-vulkan profiles that used to set its classifier here now live on
srcmorph/pom.xml, since the classifier choice is resolved at srcmorph's own build. -->
<!-- Default AI model definition (key) used by the gpt-oss profile's generate/aggregate executions.
gpt-oss-20B-mxfp4 is the native MXFP4 format: same ~12 GB size and decode speed as the Q4/Q5/Q8
variants (the MoE experts are MXFP4 regardless), but no double-quantization of the experts ->
best quality. Override with -Dai.model=gpt-oss-20B-Q4_K_M (or any key in <aiDefinitions>). -->
<ai.model>gpt-oss-20B-mxfp4</ai.model>
<!-- GPU layer offload for the gpt-oss presets (the gpu-layers / n_gpu_layers flag). -1 (default) =
do NOT pin a count, so llama.cpp AUTO-FITS as many layers as fit the card's free VRAM. This is
the robust "runs on any card" setting: it never over-commits (no OOM on a 6 GB card) and uses
more layers on a bigger card. A CPU build stays on CPU. Pin a count only to force a specific
partial split (e.g. -Dai.gpuLayers=12); a fixed count disables auto-fit. GPU classifier only. -->
<ai.gpuLayers>-1</ai.gpuLayers>
<!-- Primary GPU index for the gpt-oss presets (the main-gpu flag). -1 = leave default. Matters on
multi-GPU hosts: a Vulkan build enumerates every GPU (an integrated GPU may be device 0), so
the default can pick the slower one. Set e.g. -Dai.mainGpu=1 to force the discrete GPU. A CUDA
build only enumerates NVIDIA devices, so a single-NVIDIA host needs no setting. -->
<ai.mainGpu>-1</ai.mainGpu>
<!-- Explicit device selection for the gpt-oss presets (the device flag); comma-separated backend
device names (e.g. Vulkan1). Empty = leave default. Takes precedence over ai.mainGpu. -->
<ai.devices></ai.devices>
<junit.version>6.1.2</junit.version>
<hamcrest.version>3.0</hamcrest.version>
<jmh.version>1.37</jmh.version>
<jcstress.version>0.16</jcstress.version>
<vmlens.version>1.2.28</vmlens.version>
<errorprone.version>2.50.0</errorprone.version>
<nullaway.version>0.13.7</nullaway.version>
<jspecify.version>1.0.0</jspecify.version>
<checker.version>4.2.1</checker.version>
<!-- jqwik / Lincheck are no longer dependencies of this module (both moved to srcmorph
with the config package's tests); see srcmorph/pom.xml for the jqwik "DO NOT UPGRADE
past 1.9.3" policy note (CLAUDE.md "jqwik prompt-injection in test output"). -->
<archunit.version>1.4.2</archunit.version>
<spotbugs.version>4.10.2.0</spotbugs.version>
<lombok.version>1.18.46</lombok.version>
<fb-contrib.version>7.7.4</fb-contrib.version>
<findsecbugs.version>1.14.0</findsecbugs.version>
<spotless.version>3.8.0</spotless.version>
<palantir-java-format.version>2.94.0</palantir-java-format.version>
<ai.index.output.directory>${project.basedir}/src/site/ai</ai.index.output.directory>
<!-- Prompt-cache toggle (default on). Reuses the shared prompt-template prefix KV across
files. Override per run for benchmarking, e.g. -Dai.cachePrompt=false. -->
<ai.cachePrompt>true</ai.cachePrompt>
<!-- EXPERIMENT KNOBS (commented out, kept for re-runs). Re-enable these and switch
the executions' aiDefinitionKey/promptKey back to ${exp.model}/${exp.filePrompt}/
${exp.pkgPrompt} to drive model + prompt per run via -D for benchmarking, e.g.:
-Dexp.model=EXP-Granite-4.0-H-Tiny -Dexp.filePrompt=file-body-java-v2
-Dexp.pkgPrompt=package-body-v2 -Dai.index.output.directory=.../src/site/ai__run1
<exp.model>Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL-C64k</exp.model>
<exp.filePrompt>file-body-java</exp.filePrompt>
<exp.pkgPrompt>package-body</exp.pkgPrompt>
-->
<project.build.outputTimestamp>2026-07-15T22:33:37Z</project.build.outputTimestamp>
</properties>
<!--
slf4j-api / logback-classic convergence pins now live in the parent's
<dependencyManagement> (net.ladenthin:srcmorph-parent) so every reactor module shares them.
-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>${jspecify.version}</version>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>${checker.version}</version>
</dependency>
<!--
The extracted core library: config/document/indexer/prompt/provider/support and the
Mojo-visible framework-free API (incl. the net.ladenthin:llama JNI binding, which only
the provider package touches). Compile scope: Mojo classes construct SourceFileIndexer,
PackageIndexer, ProjectIndexer, the *Support classes, etc. directly.
-->
<dependency>
<groupId>net.ladenthin</groupId>
<artifactId>srcmorph</artifactId>
<version>${project.version}</version>
</dependency>
<!--
Already pulled in transitively via srcmorph's compile-scope dependency, but declared
explicitly here because PluginArchitectureTest imports org.slf4j.Logger directly (its
loggersArePrivateStaticFinal ArchTest rule). Version is pinned in the parent's
<dependencyManagement> for convergence.
-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>${maven.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>${maven.plugin.tools.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<!--
net.jqwik / org.jetbrains.lincheck / ch.qos.logback are deliberately NOT declared here:
after the srcmorph extraction, no test remaining in this module uses jqwik properties,
Lincheck (AiGenerationKindLincheckTest moved to srcmorph with the config package), or a
logback ListAppender (AiFieldGenerationSupportTest moved to srcmorph too). jqwik is still
named as a string literal in PluginArchitectureTest's noTestFrameworksInProduction rule,
which needs no dependency on the jar itself.
-->
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>${archunit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jcstress</groupId>
<artifactId>jcstress-core</artifactId>
<version>${jcstress.version}</version>
<scope>test</scope>
</dependency>
<!--
vmlens interleaving-analysis API. Test-scoped and transitive-dependency-free
(its own deps are all test-scope, hence not propagated), so it is safe on the
default test classpath under dependencyConvergence. Needed so the
VmlensInterleavingSmoke* test compiles in every build; it is only *executed*
under the `vmlens` profile (see that profile + the vmlens CI job). The default
surefire run excludes it (managed surefire <excludes> below) so the vmlens
agent's JDK 9 API class is never loaded outside the agent-driven run.
-->
<dependency>
<groupId>com.vmlens</groupId>
<artifactId>api</artifactId>
<version>${vmlens.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>${spotless.version}</version>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${spotbugs.version}</version>
</plugin>
<plugin>
<groupId>com.vmlens</groupId>
<artifactId>vmlens-maven-plugin</artifactId>
<version>${vmlens.version}</version>
</plugin>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
<version>10.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.6.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.8</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.12.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>${maven.plugin.tools.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.6</version>
<configuration>
<!--
argLine starts with @{argLine} so the JaCoCo agent (placed into the
argLine property by jacoco:prepare-agent) survives via late property
replacement; dropping it would detach the agent and break coverage.
The remaining flags add cross-repo-standard test JVM diagnostics:
a 2 GB heap cap, a heap dump on OutOfMemoryError into the working
directory, and a JVM fatal-error log named per crashing PID.
-->
<argLine>@{argLine} -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=. -XX:ErrorFile=hs_err_pid%p.log</argLine>
<!--
The vmlens interleaving smoke test is meaningful only when run
under the vmlens agent (the `vmlens` profile / CI job). Without the
agent its AllInterleavings loop body never executes (a vacuous pass
that also prints an "agent not configured" warning), so exclude it
from the ordinary surefire run. The vmlens job re-includes it with
`-Dtest=...`, which overrides this exclude.
-->
<excludes>
<exclude>**/VmlensInterleavingSmokeTest.java</exclude>
</excludes>
<!--
Force classpath-mode test execution, matching the same setting (and
rationale) in srcmorph/pom.xml and srcmorph-cli/pom.xml: this module's
module-info.java declares a real (non-static) `requires
net.ladenthin.srcmorph`, which is enough to make Surefire's module-path
auto-detection patch test-classes into the named module — and that
patched module then also needs every test-only dependency (e.g.
archunit-junit5) explicitly readable, which module-info intentionally
does not declare (it is release metadata for module-path consumers
only; Maven itself always loads this plugin classpath-only). Classpath
mode matches how this module is actually built/tested/consumed.
-->
<useModulePath>false</useModulePath>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.6.3</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.15</version>
</plugin>
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.25.7</version>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.11.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
<executions>
<execution>
<id>get-git-properties</id>
<goals>
<goal>revision</goal>
</goals>
<phase>initialize</phase>
</execution>
</executions>
<configuration>
<dateFormat>yyyy-MM-dd'T'HH:mm:ss'Z'</dateFormat>
<dateFormatTimeZone>UTC</dateFormatTimeZone>
<generateGitPropertiesFile>false</generateGitPropertiesFile>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-maven</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.6.3,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[1.8,)</version>
</requireJavaVersion>
<dependencyConvergence/>
<bannedDependencies>
<excludes>
<!-- Use SLF4J directly; never commons-logging. -->
<exclude>commons-logging:commons-logging</exclude>
<!-- Legacy / EoL logging frameworks. -->
<exclude>log4j:log4j</exclude>
<!-- Old hamcrest split artifacts; use hamcrest:hamcrest 2.x+. -->
<exclude>org.hamcrest:hamcrest-core</exclude>
<exclude>org.hamcrest:hamcrest-library</exclude>
<exclude>org.hamcrest:hamcrest-all</exclude>
<!-- Legacy JUnit 3 / 4; we use Jupiter (junit:junit-jupiter). -->
<exclude>junit:junit</exclude>
<exclude>junit:junit-dep</exclude>
</excludes>
</bannedDependencies>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>${maven.compiler.release}</release>
<testRelease>${maven.compiler.testRelease}</testRelease>
<showWarnings>true</showWarnings>
<parameters>true</parameters>
<compilerArgs>
<!--
-Xlint:all surfaces every category of javac warning. Excluded categories:
-serial : serialVersionUID warnings on non-Serializable classes
-options : bootclasspath / target-mismatch chatter under release=8
-classfile : noise when javac reads our own .class output mid-build
-processing: "No processor claimed any of these annotations" (Error
Prone's @GuardedBy is consumed by the EP javac plugin,
not by a JSR-269 annotation processor)
-Werror is on: the ElementType.MODULE blocker is gone now that
@NullMarked lives only in module-info.java (compiled at release 9 in a
separate execution); see module-info.java's javadoc.
-->
<arg>-Xlint:all,-serial,-options,-classfile,-processing</arg>
<arg>-Werror</arg>
<!-- Explicit processor list: Lombok (two SPI classes) + Checker Framework's
Nullness Checker as a 2nd nullness pass alongside NullAway. The explicit
-processor argument overrides SPI discovery, so every processor we want
to run must be listed here. -->
<arg>-processor</arg>
<arg>lombok.launch.AnnotationProcessorHider$AnnotationProcessor,lombok.launch.AnnotationProcessorHider$ClaimingProcessor,org.checkerframework.checker.nullness.NullnessChecker</arg>
<!-- Skip CF analysis of the auto-generated HelpMojo (target/generated-sources/plugin/...).
The plugin-tools-generated code is not under our control and has its own
initialization patterns Maven handles via reflection. -->
<arg>-AskipDefs=^net\.ladenthin\.srcmorph_maven_plugin\..*$</arg>
<arg>-XDaddTypeAnnotationsToSymbol=true</arg>
<arg>-XDcompilePolicy=simple</arg>
<arg>--should-stop=ifError=FLOW</arg>
<!-- XepExcludedPaths skips the auto-generated HelpMojo for Error Prone
(parallels the -AskipDefs above for Checker Framework). The two
remaining warnings on that file (StringSplitter) would otherwise
break -Werror. -->
<arg>-Xplugin:ErrorProne -XepExcludedPaths:.*/generated-sources/.* -Xep:NullAway:ERROR -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:ExcludedFieldAnnotations=org.apache.maven.plugins.annotations.Parameter,org.apache.maven.plugins.annotations.Component -XepOpt:NullAway:JSpecifyMode=true -XepOpt:NullAway:CheckOptionalEmptiness=true -XepOpt:NullAway:AcknowledgeRestrictiveAnnotations=true -XepOpt:NullAway:AcknowledgeAndroidRecent=true -XepOpt:NullAway:AssertsEnabled=true -Xep:BoxedPrimitiveEquality:ERROR -Xep:EqualsHashCode:ERROR -Xep:EqualsIncompatibleType:ERROR -Xep:IdentityBinaryExpression:ERROR -Xep:SelfAssignment:ERROR -Xep:SelfComparison:ERROR -Xep:SelfEquals:ERROR -Xep:DeadException:ERROR -Xep:FormatString:ERROR -Xep:InvalidPatternSyntax:ERROR -Xep:OptionalEquality:ERROR -Xep:ImpossibleNullComparison:ERROR</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${errorprone.version}</version>
</path>
<path>
<groupId>com.uber.nullaway</groupId>
<artifactId>nullaway</artifactId>
<version>${nullaway.version}</version>
</path>
<path>
<groupId>org.checkerframework</groupId>
<artifactId>checker</artifactId>
<version>${checker.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<!-- The default compile pass targets Java 8 bytecode for the plugin
sources. module-info.java cannot be compiled at release 8 (it is a
Java 9+ construct) and is handled by the separate execution below. -->
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
</execution>
<execution>
<id>module-info-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<!-- module-info.java is the only Java 9+ source in this project; compile
it at release 9 (the minimum version that understands modules) without
the Error Prone / NullAway / Checker Framework processors that target
ordinary source files only. Java 8 runtimes silently ignore the
resulting module-info.class at the JAR root, so Maven (which loads
plugins classpath-only) continues to work unchanged. -->
<release>9</release>
<includes>
<include>module-info.java</include>
</includes>
<compilerArgs combine.self="override"/>
<annotationProcessorPaths combine.self="override"/>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<configuration>
<!-- Drop -parameters for test compile so jcstress / Lincheck reflection
doesn't pick up parameter names from MethodParameters. -->
<parameters>false</parameters>
<compilerArgs combine.self="override">
<arg>-XDaddTypeAnnotationsToSymbol=true</arg>
<arg>-XDcompilePolicy=simple</arg>
<arg>--should-stop=ifError=FLOW</arg>
<arg>-Xplugin:ErrorProne -Xep:NullAway:OFF -Xep:GuardedBy:OFF -Xep:IdentityBinaryExpression:OFF</arg>
</compilerArgs>
<annotationProcessorPaths combine.children="append">
<path>
<groupId>org.openjdk.jcstress</groupId>
<artifactId>jcstress-core</artifactId>
<version>${jcstress.version}</version>
</path>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<!--
Must run at package (jar-no-fork's own default phase), NOT verify.
maven-gpg-plugin's sign-artifacts execution (release profile) is bound
to verify; package always runs before verify in the lifecycle, so the
sources jar must be built and attached here to exist before signing
runs. Binding this to verify put it in the SAME phase as gpg:sign,
and — since the parent's inherited gpg execution ran first — gpg
signed only the main jar + javadoc jar + pom, silently omitting the
sources jar. Sonatype Central's deployment validation then rejected
the whole bundle for a missing signature (caught on the first real
release attempt; not visible in any dry run that passed -Dgpg.skip=true,
which also skips the real execution-order interaction).
-->
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<source>${maven.compiler.release}</source>
<failOnError>true</failOnError>
<failOnWarnings>true</failOnWarnings>
<doclint>all</doclint>
<sourceFileExcludes>
<sourceFileExclude>**/HelpMojo.java</sourceFileExclude>
</sourceFileExcludes>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<configuration>
<goalPrefix>srcmorph</goalPrefix>
</configuration>
<executions>
<execution>
<id>default-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
</execution>
<execution>
<id>help-goal</id>
<goals>
<goal>helpmojo</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<configuration>
<java>
<includes>
<include>src/main/java/**/*.java</include>
<include>src/test/java/**/*.java</include>
</includes>
<palantirJavaFormat>
<version>${palantir-java-format.version}</version>
</palantirJavaFormat>
<removeUnusedImports/>
<trimTrailingWhitespace/>
<endWithNewline/>
</java>
</configuration>
<executions>
<execution>
<id>spotless-check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<failOnError>true</failOnError>
<includeTests>false</includeTests>
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
<plugins>
<plugin>
<groupId>com.mebigfatguy.fb-contrib</groupId>
<artifactId>fb-contrib</artifactId>
<version>${fb-contrib.version}</version>
</plugin>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>${findsecbugs.version}</version>
</plugin>
</plugins>
</configuration>
<executions>
<execution>
<id>spotbugs-check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>org.openjdk.jmh.Main</mainClass>
<classpathScope>test</classpathScope>
</configuration>
</plugin>
<!--
No pitest-maven execution here: every class that was gated at 100% PIT mutation
parity in this pom (config/document/indexer/prompt/provider/support) moved to the
srcmorph module — see srcmorph/pom.xml for the full targetClasses list. Nothing in
the remaining mojo package has PIT coverage yet. Add a mojo-focused pitest-maven
execution here once mojo classes are covered (Mojos are typically integration-tested
via Maven invoker/executor rather than unit-mutation-tested, so this may stay empty
by design — revisit before assuming that's the reason).
-->
</plugins>
</build>
<profiles>
<!--
The gpu-cuda / gpu-vulkan profiles (setting a GPU classifier on net.ladenthin:llama)
moved to srcmorph/pom.xml, since only that module's provider package depends on
net.ladenthin:llama now. To index with a GPU-accelerated model, build srcmorph with
that profile active first (e.g. `cd ../srcmorph && mvn install -P gpu-cuda`), then run
this module's srcmorph-selftest profile as usual — the ai.gpuLayers / ai.mainGpu /
ai.devices properties consumed below are unaffected and still live in this pom.
The `release` profile (GPG signing + central-publishing-maven-plugin) now lives in the
parent (net.ladenthin:srcmorph-parent) so a single `mvn -P release deploy` from the
reactor root signs and publishes every module.
-->
<profile>
<id>srcmorph-selftest</id>
<build>
<plugins>
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<configuration>
<outputDirectory>${ai.index.output.directory}</outputDirectory>
<!-- EXPERIMENT SCOPE (claude2026_06_26_00): config + provider only,
a diverse 12-file mix for fast model/prompt comparison. Restore the
single aiindex subtree for a full self-index.
UPDATED (srcmorph core-module extraction, step 4): config and
provider now live in the sibling srcmorph module, not under this
module's own basedir, so the subtrees below reach across the
reactor via a relative ".." path (AbstractAiIndexMojo resolves
subtrees with basePath.resolve(subtree).normalize(), which permits
".." segments). This profile still runs `mvn srcmorph:generate -P
srcmorph-selftest` from THIS module (it invokes this plugin's own
goals), it just indexes source that now lives one directory up. -->
<subtrees>
<subtree>../srcmorph/src/main/java/net/ladenthin/srcmorph/config</subtree>
<subtree>../srcmorph/src/main/java/net/ladenthin/srcmorph/provider</subtree>
</subtrees>
<!-- EXPERIMENT FILTERING (claude2026_06_26_00): drop package-info/module-info;
they carry no public API and only add padded near-empty summaries. -->
<excludes>
<exclude>**/package-info.java</exclude>
<exclude>**/module-info.java</exclude>
</excludes>
<generationProvider>llamacpp-jni</generationProvider>
<!--
AI model definitions: define each model once and reference it by key.
No Maven profiles or properties are needed for model configuration.
maxInputChars is calculated automatically from contextSize,
maxOutputTokens, charsPerToken, and the prompt template length.
-->
<aiDefinitions>
<!--
============================================================
MODEL SELECTION GUIDE - pros / cons / when to pick each
============================================================
This plugin runs local GGUF models, typically CPU-only, to
summarize source files (Phase 1) and packages (Phase 2). The
three levers that matter on CPU: (1) ACTIVE parameter count
(MoE models activate only a fraction per token, so they decode
far faster than a dense model of the same total size); (2)
ATTENTION type for long context (Mamba-hybrid and GQA keep the
KV cache small, so big windows stay affordable); (3) quant level
(Q4_K_M = best size/quality balance, Q5/Q6 = more fidelity, more
RAM + slower). Pick by key from the entries below.
QUICK CHOOSER
Fastest / least RAM ............ Qwen3-4B-Instruct-2507 (Q5_K_M)
Best CPU code (recommended) .... Qwen3-Coder-30B-A3B (Q4_K_M, MoE ~3B active)
Largest context on CPU ......... Granite-4.0-H-Tiny (128K, Mamba-hybrid, flat KV)
Best dense code @ ~16 GB ....... Qwen2.5-Coder-14B / Codestral-22B
Best general prose summaries ... Gemma-4-12B-it / Ministral-3-14B
Max quality, still CPU-able .... Gemma-4-26B-A4B (MoE) / Granite-4.0-H-Small
PER-MODEL NOTES (key -> pro / con / use when)
Mistral-7B-Instruct-v0.3-Q4_K_M-C16k
+ Tiny, fast, rock-stable baseline; great instruction following.
- Not code-specialized; only 16K context; older than the Qwen3 tier.
Use when: you want a known-good, low-risk general summarizer.
Meta-Llama-3.1-8B-Instruct-Q5_K_M-C32k
+ Strong general model, 32K context, broad ecosystem support.
- Generic (not code-tuned); 8B dense is slower than the MoE picks.
Use when: mixed prose + code and you trust the Llama family.
Codestral-22B-v0.1-Q4_K_M-C32k / -Q6_K-C32k
+ Purpose-built code model (FIM-aware), excellent at code structure.
- 22B DENSE = heavy/slow on CPU; Q6_K variant is higher fidelity but
even slower and larger (pick Q4_K for speed, Q6_K only if quality
gaps show). Non-commercial license (MNPL) - check before shipping.
Use when: code quality matters more than speed and you have RAM.
Qwen2.5-Coder-7B-Instruct-Q5_K_M-C16k
+ Best-in-class small CODE model; fast; tight instruction following.
- 16K context; superseded on quality by the 14B and Qwen3 entries.
Use when: fast per-file code summaries on modest hardware.
Ministral-3-8B / 14B-Instruct-2512 (Q4_K_M and Q5_K_M, C32k)
+ Modern dense Mistral; 14B rivals much larger models; low temp = stable.
- Dense (no MoE speedup); repo may be GATED on HuggingFace (needs login);
Q5_K_M trades speed for a little extra fidelity over Q4_K_M.
Use when: you want current Mistral quality; 14B for best, 8B for speed.
Gemma-4-26B-A4B-it-UD-Q4_K_M-C32k
+ MoE 26B total / ~4B active: near-27B-dense quality at ~4B-dense SPEED.
One of the best quality-per-CPU-second options here.
- Larger download/RAM than the small dense models; needs temp = 1.0
(lowering it degrades Gemma 4); 32K context.
Use when: you want top quality but cannot afford a slow dense 20B+.
Gemma-4-12B-it-Q4_K_M-C32k
+ Excellent dense generalist for readable prose summaries.
- 12B dense is slower than the MoE picks; temp must stay at 1.0.
Use when: package-level prose quality is the priority.
Gemma-4-E4B-Uncensored-...-Q4_K_M / -Q6_K_P (C32k)
+ ~4B effective (MoE), very light; uncensored derivative avoids refusals
on edged content; Q6_K_P is a near-lossless custom quant (~1-2 quant
levels better for only 5-15% more size).
- Community/uncensored build (less vetted); quality below the larger
Gemma 4 entries; only pick Q6_K_P if Q4_K_M quality is visibly short.
Use when: a light model keeps refusing, or you need the lightest Gemma 4.
Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL-C64k (throughput-optimal alternative; gpt-oss-20B-c96k is now the ACTIVE default)
+ MoE 30B total / ~3.3B active: code-specialized AND fast on CPU; fewer
active params than Gemma-4-26B-A4B; non-thinking; Apache-2.0.
+ Locally present (X:/Modelle/Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf,
17.7 GB); 64K context - generous but CPU-feasible (256K prefill is unusable on CPU).
- Needs Qwen sampling (temp 0.7 / top_p 0.8 / top_k 20 / repeat 1.05).
Use when: this is the go-to for most code summarization on CPU.
Qwen2.5-Coder-14B-Instruct-Q4_K_M-C32k
+ The cited top LOCAL dense code model at the 16 GB tier; big step up
from the 7B entry.
- 14B dense is slower than the MoE Qwen3-Coder; 32K context.
Use when: you prefer a dense code model and have ~16 GB to spare.
Qwen3-4B-Instruct-2507-Q5_K_M-C32k
+ Smallest/fastest here (2.89 GB), Apache-2.0, NON-thinking (no <think>
noise); punches well above 4B on instruction following.
- Lowest ceiling on hard reasoning / large files.
Use when: laptop / low-RAM, or you want maximum throughput per file.
Granite-4.0-H-Tiny-Q4_K_M-C128k (best LARGE context on CPU)
+ Hybrid Mamba-2/Transformer, ~1B active of 7B: KV memory stays ~FLAT as
context grows, so 128K is cheap on CPU; Apache-2.0; very fast.
- General (not code-specialized); summary quality below the big coders.
Use when: you need long context with the least CPU/RAM cost.
Granite-4.0-H-Small-Q4_K_M-C128k
+ Same flat-KV long-context benefit with more capacity (~9B active of 32B).
- Heavier active count = slower per token than H-Tiny; larger download.
Use when: you want long context AND more quality than H-Tiny gives.
-->
<!-- Mistral-7B-Instruct-v0.3-Q4_K_M (16 K context)
https://huggingface.co/lmstudio-community/Mistral-7B-Instruct-v0.3-GGUF/blob/main/Mistral-7B-Instruct-v0.3-Q4_K_M.gguf -->
<aiDefinition>
<key>Mistral-7B-Instruct-v0.3-Q4_K_M-C16k</key>
<modelPath>X:/Modelle/Mistral-7B-Instruct-v0.3-Q4_K_M.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- bartowski/Meta-Llama-3.1-8B-Instruct-GGUF
https://huggingface.co/bartowski/Meta-Llama-3.1-8B-Instruct-GGUF/blob/main/Meta-Llama-3.1-8B-Instruct-Q5_K_M.gguf -->
<aiDefinition>
<key>Meta-Llama-3.1-8B-Instruct-Q5_K_M-C32k</key>
<modelPath>X:/Modelle/Meta-Llama-3.1-8B-Instruct-Q5_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Codestral-22B-v0.1-Q4_K_M (32 K context)
https://huggingface.co/bartowski/Codestral-22B-v0.1-GGUF/blob/main/Codestral-22B-v0.1-Q4_K_M.gguf -->
<aiDefinition>
<key>Codestral-22B-v0.1-Q4_K_M-C32k</key>
<modelPath>X:/Modelle/Codestral-22B-v0.1-Q4_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Codestral-22B-v0.1-Q6_K (32 K context)
https://huggingface.co/bartowski/Codestral-22B-v0.1-GGUF/blob/main/Codestral-22B-v0.1-Q6_K.gguf -->
<aiDefinition>
<key>Codestral-22B-v0.1-Q6_K-C32k</key>
<modelPath>X:/Modelle/Codestral-22B-v0.1-Q6_K.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Qwen2.5-Coder-7B-Instruct-Q5_K_M (16 K context)
https://huggingface.co/Qwen/Qwen2.5-Coder-7B-Instruct-GGUF/blob/main/qwen2.5-coder-7b-instruct-q5_k_m.gguf -->
<aiDefinition>
<key>Qwen2.5-Coder-7B-Instruct-Q5_K_M-C16k</key>
<modelPath>X:/Modelle/qwen2.5-coder-7b-instruct-q5_k_m.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Ministral-3-8B-Instruct-2512-Q4_K_M (32 K context)
8.4B language model + 0.4B vision encoder; supports 256k context window.
Temperature < 0.1 recommended for production (mistral.ai/news/mistral-3).
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/mistralai/Ministral-3-8B-Instruct-2512-GGUF -->
<aiDefinition>
<key>Ministral-3-8B-Instruct-2512-Q4_K_M-C32k</key>
<modelPath>X:/Modelle/Ministral-3-8B-Instruct-2512-Q4_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.1</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Ministral-3-14B-Instruct-2512-Q4_K_M (32 K context)
13.5B language model + 0.4B vision encoder; supports 256k context window.
Comparable performance to Mistral Small 3.2 24B at lower resource cost.
Temperature < 0.1 recommended for production (mistral.ai/news/mistral-3).
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/mistralai/Ministral-3-14B-Instruct-2512-GGUF -->
<aiDefinition>
<key>Ministral-3-14B-Instruct-2512-Q4_K_M-C32k</key>
<modelPath>X:/Modelle/Ministral-3-14B-Instruct-2512-Q4_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.1</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Ministral-3-8B-Instruct-2512-Q5_K_M (32 K context)
8.4B language model + 0.4B vision encoder; supports 256k context window.
Temperature < 0.1 recommended for production (mistral.ai/news/mistral-3).
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/mistralai/Ministral-3-8B-Instruct-2512-GGUF -->
<aiDefinition>
<key>Ministral-3-8B-Instruct-2512-Q5_K_M-C32k</key>
<modelPath>X:/Modelle/Ministral-3-8B-Instruct-2512-Q5_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.1</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Ministral-3-14B-Instruct-2512-Q5_K_M (32 K context)
13.5B language model + 0.4B vision encoder; supports 256k context window.
Comparable performance to Mistral Small 3.2 24B at lower resource cost.
Temperature < 0.1 recommended for production (mistral.ai/news/mistral-3).
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/mistralai/Ministral-3-14B-Instruct-2512-GGUF -->
<aiDefinition>
<key>Ministral-3-14B-Instruct-2512-Q5_K_M-C32k</key>
<modelPath>X:/Modelle/Ministral-3-14B-Instruct-2512-Q5_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.1</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- gemma-4-26B-A4B-it-UD-Q4_K_M (32 K context)
26B total / ~4B active parameters (MoE: 128 experts, 8+1 active per token).
Runs at the computational cost of a ~4B dense model; quality near 27B dense.
Temperature 1.0 is critical for Gemma 4 - lowering degrades quality.
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/unsloth/gemma-4-26B-A4B-it-GGUF -->
<aiDefinition>
<key>Gemma-4-26B-A4B-it-UD-Q4_K_M-C32k</key>
<modelPath>X:/Modelle/gemma-4-26B-A4B-it-UD-Q4_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>8192</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.95</topP>
<topK>64</topK>
<repeatPenalty>1.1</repeatPenalty>
<chatTemplateEnableThinking>false</chatTemplateEnableThinking>
<stopStrings>
<stopString><end_of_turn></stopString>
</stopStrings>
</aiDefinition>
<!-- gemma-4-12B-it-Q4_K_M (32 K context)
12B dense instruction-tuned model from Google DeepMind.
Temperature 1.0 is critical for Gemma 4 - lowering degrades quality.
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/bartowski/gemma-4-12B-it-GGUF -->
<aiDefinition>
<key>Gemma-4-12B-it-Q4_K_M-C32k</key>
<modelPath>X:/Modelle/gemma-4-12B-it-Q4_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>8192</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.95</topP>
<topK>64</topK>
<repeatPenalty>1.1</repeatPenalty>
<chatTemplateEnableThinking>false</chatTemplateEnableThinking>
<stopStrings>
<stopString><end_of_turn></stopString>
</stopStrings>
</aiDefinition>
<!-- Gemma-4-E4B-Uncensored-HauhauCS-Aggressive-Q4_K_M (32 K context)
~4B effective parameters (MoE); uncensored derivative of gemma-4-E4B-it.
Temperature 1.0 is critical for Gemma 4 - lowering degrades quality.
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/HauhauCS/Gemma-4-E4B-Uncensored-HauhauCS-Aggressive -->
<aiDefinition>
<key>Gemma-4-E4B-Uncensored-HauhauCS-Aggressive-Q4_K_M-C32k</key>
<modelPath>X:/Modelle/Gemma-4-E4B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>8192</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.95</topP>
<topK>64</topK>
<repeatPenalty>1.1</repeatPenalty>
<chatTemplateEnableThinking>false</chatTemplateEnableThinking>
<stopStrings>
<stopString><end_of_turn></stopString>
</stopStrings>
</aiDefinition>
<!-- Gemma-4-E4B-Uncensored-HauhauCS-Aggressive-Q6_K_P (32 K context)
Same model as Q4_K_M above; Q6_K_P is a custom lossless quantization by HauhauCS
that preserves quality where it matters most (effectively 1-2 quant levels higher
at only 5-15 % larger file size).
Temperature 1.0 is critical for Gemma 4 - lowering degrades quality.
32k context is a practical sweet spot for code summarization on local hardware.
https://huggingface.co/HauhauCS/Gemma-4-E4B-Uncensored-HauhauCS-Aggressive -->
<aiDefinition>
<key>Gemma-4-E4B-Uncensored-HauhauCS-Aggressive-Q6_K_P-C32k</key>
<modelPath>X:/Modelle/Gemma-4-E4B-Uncensored-HauhauCS-Aggressive-Q6_K_P.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>8192</maxOutputTokens>
<temperature>1.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.95</topP>
<topK>64</topK>
<repeatPenalty>1.1</repeatPenalty>
<chatTemplateEnableThinking>false</chatTemplateEnableThinking>
<stopStrings>
<stopString><end_of_turn></stopString>
</stopStrings>
</aiDefinition>
<!-- Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL (64 K context) - the
locally-present file and the active model for BOTH AI phases
(file-body + package-body). MoE 30B total / ~3.3B active,
non-thinking (emits no <think> blocks, so no enable_thinking flag
is needed or set), Apache-2.0. Unsloth Dynamic UD-Q4_K_XL quant,
single-file GGUF (17.7 GB) at
X:/Modelle/Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf.
Official Qwen3-Coder sampling (model card): temperature 0.7,
top_p 0.8, top_k 20, repetition_penalty 1.05.
Context: native window is 262144; 64 K is a deliberate, generous
yet CPU-feasible cap - 256 K prefill is unusable on CPU.
maxOutputTokens is deliberately 1536 (NOT the model card's generic
65536): the purpose here is short, dense bullet-point summaries,
not long code generations, so a tight output cap keeps each
generation fast and on-topic.
https://huggingface.co/unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF -->
<aiDefinition>
<key>Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL-C64k</key>
<modelPath>X:/Modelle/Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf</modelPath>
<!-- Context 16384 is the practical CPU default on this machine: the 64K
KV cache (~6 GB) pushed total memory over the edge and caused paging,
while 16K fits comfortably (~18 GB total) and still covers every source
file here. Raise to 65536 only with enough free RAM headroom. The
"-C64k" key suffix is left as-is to avoid re-pointing the executions. -->
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.8</topP>
<topK>20</topK>
<repeatPenalty>1.05</repeatPenalty>
<cachePrompt>${ai.cachePrompt}</cachePrompt>
</aiDefinition>
<!-- Qwen2.5-Coder-14B-Instruct-Q4_K_M (32 K context)
Dense 14B, the cited top local coding model at the 16 GB tier;
upgrade of the Qwen2.5-Coder-7B entry above. Single-file GGUF from
bartowski (the official Qwen repo splits Q5_K_M into two parts). Download:
https://huggingface.co/bartowski/Qwen2.5-Coder-14B-Instruct-GGUF/resolve/main/Qwen2.5-Coder-14B-Instruct-Q4_K_M.gguf -->
<aiDefinition>
<key>Qwen2.5-Coder-14B-Instruct-Q4_K_M-C32k</key>
<modelPath>X:/Modelle/Qwen2.5-Coder-14B-Instruct-Q4_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.8</topP>
<topK>20</topK>
<repeatPenalty>1.05</repeatPenalty>
</aiDefinition>
<!-- Qwen3-4B-Instruct-2507-Q5_K_M (32 K context)
Dense 4B, Apache-2.0, NON-thinking instruct variant (no <think> blocks) -
the fast/low-RAM tier for short structured summaries on a laptop.
Single-file GGUF (2.89 GB). Download:
https://huggingface.co/unsloth/Qwen3-4B-Instruct-2507-GGUF/resolve/main/Qwen3-4B-Instruct-2507-Q5_K_M.gguf -->
<aiDefinition>
<key>Qwen3-4B-Instruct-2507-Q5_K_M-C32k</key>
<modelPath>X:/Modelle/Qwen3-4B-Instruct-2507-Q5_K_M.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.8</topP>
<topK>20</topK>
<repeatPenalty>1.05</repeatPenalty>
</aiDefinition>
<!-- Granite-4.0-H-Tiny-Q4_K_M (128 K context)
7B total / ~1B active, hybrid Mamba-2/Transformer, Apache-2.0.
128 K validated (512 K trained). Mamba layers keep KV memory ~flat with
context, making this the most CPU-performant LARGE-context option.
Low temperature for deterministic summaries. Single-file GGUF. Download:
https://huggingface.co/bartowski/ibm-granite_granite-4.0-h-tiny-GGUF/resolve/main/ibm-granite_granite-4.0-h-tiny-Q4_K_M.gguf -->
<aiDefinition>
<key>Granite-4.0-H-Tiny-Q4_K_M-C128k</key>
<modelPath>X:/Modelle/ibm-granite_granite-4.0-h-tiny-Q4_K_M.gguf</modelPath>
<contextSize>131072</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.2</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- Granite-4.0-H-Small-Q4_K_M (128 K context)
32B total / ~9B active, hybrid Mamba-2/Transformer, Apache-2.0, 128 K.
More quality headroom than H-Tiny while staying memory-flat at long
context; heavier active count so slower per-token on CPU. Download:
https://huggingface.co/bartowski/ibm-granite_granite-4.0-h-small-GGUF/resolve/main/ibm-granite_granite-4.0-h-small-Q4_K_M.gguf -->
<aiDefinition>
<key>Granite-4.0-H-Small-Q4_K_M-C128k</key>
<modelPath>X:/Modelle/ibm-granite_granite-4.0-h-small-Q4_K_M.gguf</modelPath>
<contextSize>131072</contextSize>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.2</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<repeatPenalty>1.1</repeatPenalty>
</aiDefinition>
<!-- ============================================================
EXPERIMENT MODELS (claude2026_06_26_00)
All at context 16384 for an apples-to-apples, RAM-safe,
fast comparison. Selected by -Dexp.model=<key>.
============================================================ -->
<aiDefinition>
<key>EXP-Qwen3.5-4B</key>
<modelPath>X:/Modelle/Qwen3.5-4B-Q4_K_M.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.8</topP>
<topK>20</topK>
<repeatPenalty>1.05</repeatPenalty>
<chatTemplateEnableThinking>false</chatTemplateEnableThinking>
</aiDefinition>
<aiDefinition>
<key>EXP-Qwen2.5-Coder-7B</key>
<modelPath>X:/Modelle/qwen2.5-coder-7b-instruct-q5_k_m.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.8</topP>
<topK>20</topK>
<repeatPenalty>1.05</repeatPenalty>
</aiDefinition>
<!-- ============================================================
gpt-oss-20B - three ready-to-use presets, tiered by the LARGEST
source file you need to cover. All use reasoningEffort=low: the
benchmark (docs/ai-index-benchmark/COMPARISON.md section 11) shows low is
best for dense code summaries - fastest, and the whole output
budget goes to the summary instead of in-band reasoning. Raise the
effort only for genuinely reasoning-heavy generation AND raise
maxOutputTokens with it, or the final answer is truncated.
>>> DEFAULT MODEL: gpt-oss-20B-mxfp4 (native MXFP4), 96K window <<<
(set via the ai.model property; the c16k/c48k/c96k presets are the
same model family at narrower windows.)
Why the widest practical window is the default: a measured A/B
(section 11) proved that a larger contextSize costs ONLY KV RAM, NOT
per-file time - for the same small file, 16K vs 96K had identical
prefill/decode/wall time; only RAM grew (~+400 MiB per +16K). So
defaulting to 96K means one preset covers EVERY file up to ~250 KB
with no trimming and no truncation, while small files stay just as
fast. The only cost is RAM you must have anyway for the big files.
Downshift to c48k / c16k ONLY to save RAM on memory-constrained
machines (model ~12 GB + KV ~2 GB @16K / ~6 GB @48K / ~11 GB @96K;
a fully filled 96K window plus context checkpoints peaks ~23 GB).
Shared design:
- charsPerToken 3 is a conservative pre-trim safety ratio: real
Java tokenizes at ~4.8 chars/token (D2; the synthetic fixture was
~4.2), so 3 under-counts on purpose, keeping the char-based pre-trim
token-safe so a big file is never silently over-fed past the real
token window. (The ETA estimator uses the measured 4.8 separately;
see AiGenerationTimeEstimator.ESTIMATION_CHARS_PER_TOKEN.)
- Sampling: temp 0.7, top-p 1.0, top-k 0, min-p 0.05. This is a
deliberate task-specific deviation from the model card's
temp 1.0/top-p 1.0: a fact-check (docs/.../gpt-oss-tuning.md D1)
found temp 1.0 loses faithfulness while greedy/temp 0 triggers
"reasoning blackhole" loops in ~81% of probed prompts; temp 0.7
with min-p 0.05 as the primary truncation is the faithful-but-safe
middle ground (min-p scales the cut-off to model confidence).
Sizing (measured: 96 KB code = ~24K tokens; model window = 131072):
c16k -> files up to ~40 KB (typical files; fast, ~1-2 min/file)
c48k -> files up to ~125 KB (large files; ~25 min for ~100 KB) [validated]
c96k -> files up to ~260 KB (DEFAULT; ~1 h for ~250 KB) [validated]
Hard ceiling: the 128K window caps input at ~480-500 KB of code, but
CPU prefill+decode time and KV RAM make ~250 KB the practical limit.
Prefill is the dominant cost on big files (O(n^2)), not the effort
level - see the estimate the plugin logs per file.
============================================================ -->
<aiDefinition>
<key>gpt-oss-20B-c16k</key>
<modelPath>X:/Modelle/gpt-oss-20b-UD-Q4_K_XL.gguf</modelPath>
<contextSize>16384</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>2048</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<aiDefinition>
<key>gpt-oss-20B-c48k</key>
<modelPath>X:/Modelle/gpt-oss-20b-UD-Q4_K_XL.gguf</modelPath>
<contextSize>49152</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>4096</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<aiDefinition>
<key>gpt-oss-20B-c96k</key>
<modelPath>X:/Modelle/gpt-oss-20b-UD-Q4_K_XL.gguf</modelPath>
<contextSize>98304</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>6144</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<!-- ============================================================
gpt-oss-20b QUANTIZATION MENU (measured: docs/.../gpt-oss-tuning.md E5)
============================================================
Same 30 KB fixture, identical settings (low effort, temp 0.7,
min-p 0.05, ctx 32768), one model load each, CPU. All produced a
complete 9/9-section summary with no retries, so QUALITY IS
QUANT-INDEPENDENT (gpt-oss is natively MXFP4 -> higher precision
adds no information). Speed is within run-to-run noise.
quant file prefill t/s decode t/s sections
mxfp4(native) 11.3 GB 36.1 5.85 9/9 <- DEFAULT (ai.model); native MXFP4, best quality
UD-Q4_K_XL 11.1 GB 35.1 6.30 9/9 <- the c16k/c48k/c96k presets above
Q4_K_M 10.8 GB 36.6 6.59 9/9 <- smallest + fastest decode (marginal)
Q5_K_M 10.9 GB 32.1 5.96 9/9
Q8_0 11.3 GB 36.3 6.24 9/9
F16 12.85 GB 39.1 5.40 9/9 <- NOT recommended: biggest + slowest, no quality gain
GPU cross-check (RTX 3070 8 GB, partial offload ngl=16, ctx 4096,
128 tok): Q4_K_M 25.4 / Q8_0 24.9 / mxfp4 23.9 decode t/s -> quant
choice is within noise on GPU too (all ~12 GB, experts are MXFP4).
Backend (mxfp4): CUDA 23.9 > Vulkan-discrete 18.1 > Vulkan-iGPU 10.0
~ CPU 8.25; with auto-fit (ngl=-1) CUDA reached 29.2. OpenCL drops
NVIDIA (unsupported) -> CPU fallback, so it is not offered.
Guidance: default is now gpt-oss-20B-mxfp4 (native format, same size +
speed as the others, no expert double-quantization -> best quality).
Switch with -Dai.model=<key> (e.g. gpt-oss-20B-Q4_K_M for a hair less
RAM). Do NOT use Q8_0/F16 - more RAM, no quality benefit. UD-Q4_K_XL is
covered by the gpt-oss-20B-c96k preset above. All defs below carry the
${ai.gpuLayers}/${ai.mainGpu}/${ai.devices} GPU knobs (ngl auto-fits).
============================================================ -->
<aiDefinition>
<key>gpt-oss-20B-mxfp4</key>
<modelPath>X:/Modelle/gpt-oss-20b-mxfp4.gguf</modelPath>
<contextSize>98304</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>6144</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<aiDefinition>
<key>gpt-oss-20B-Q4_K_M</key>
<modelPath>X:/Modelle/gpt-oss-20b-Q4_K_M.gguf</modelPath>
<contextSize>98304</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>6144</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<aiDefinition>
<key>gpt-oss-20B-Q5_K_M</key>
<modelPath>X:/Modelle/gpt-oss-20b-Q5_K_M.gguf</modelPath>
<contextSize>98304</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>6144</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<aiDefinition>
<key>gpt-oss-20B-Q8_0</key>
<modelPath>X:/Modelle/gpt-oss-20b-Q8_0.gguf</modelPath>
<contextSize>98304</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>6144</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<aiDefinition>
<key>gpt-oss-20B-F16</key>
<modelPath>X:/Modelle/gpt-oss-20b-F16.gguf</modelPath>
<contextSize>98304</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>6144</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort>low</reasoningEffort>
</aiDefinition>
<!-- ============================================================
BIG-WINDOW FALLBACK for oversized files (covers up to ~1 MB).
============================================================
A source larger than the default model's window (~275 KB for the 96K
gpt-oss presets at charsPerToken 3) hard-fails the build; the plugin
never auto-picks a model, so YOU route such files here via the
big-window rule below. IBM Granite 4.0-H-Tiny is the chosen fallback:
- Apache-2.0 (same license family as gpt-oss), IBM (not China).
- Hybrid Mamba-2/Transformer (9:1, NoPE): the KV cache grows only
LINEARLY with context, so a huge file fits ungekuerzt even on an
8 GB GPU (a classic transformer's KV would blow up at this size).
- Trained to 512K tokens (IBM validates quality to 128K), 7B/~1B-active MoE.
contextSize is set to 384K (393216) to cover files up to ~1 MB. Verified
on this machine (RTX 3070, 8 GB, CUDA, build 11): it allocated the full
393216 ctx with NO OOM (it even allocates 512K) and summarized a
~995 KB / ~268K-token Java file (prefill ~1150 t/s, ~4 min one-time;
decode ~45 t/s). Quality is best within Granite's validated 128K (~500 KB)
and degrades gradually beyond it, but a whole-file summary beats a trimmed
one. charsPerToken 3 is deliberately CONSERVATIVE (real Java is ~3.8, so
the window check over-counts tokens and never lets a file overflow the
window at run time); the cpt-3 check admits up to ~1.16 MB. reasoningEffort
is empty: Granite has no gpt-oss harmony channels, so no reasoning kwarg is
sent. The size-routing rules that target this key live in the ai-generate
<fieldGenerations> below (ids big-window-java and big-window-sql), for the
~275 KB .. ~1 MB band (one pass). Files > ~1 MB are NOT summarized in one
giant pass here (O(n^2) prefill makes that far too slow); they route to the
small-window granite-4.0-h-1b-fastchunk preset via the huge-java/huge-sql
rules and are map-reduced (cheap small chunks, maxChunks-bounded). -->
<aiDefinition>
<key>granite-4.0-h-tiny-bigwindow</key>
<modelPath>X:/Modelle/granite-4.0-h-tiny-Q4_K_M.gguf</modelPath>
<contextSize>393216</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>4096</maxOutputTokens>
<temperature>0.2</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort></reasoningEffort>
</aiDefinition>
<!-- Small/fast window for the map-reduce of VERY large files (multi-MB data),
the default fallback for oversized sources. Uses the SMALLEST Granite 4.0
hybrid (H-1B, ~1.5B, Apache-2.0, IBM) at a SMALL 16K window on purpose.
Rationale: prefill cost is O(n^2) in prompt length, so one big 384K pass is
far slower than many small 16K passes; and a tiny 1.5B model roughly doubles
CPU throughput vs the 7B/3B siblings. Chunking at ~48 KB (16K*cpt3 minus the
prompt) and capping <maxChunks> keeps a file of ANY size to a handful of cheap
calls, sampling a representative head/tail/spread - the right trade-off for
repetitive data where no precise whole-file read is needed.
MEASURED on this machine (CPU-only, 16 threads, Q4_K_M): ~175 tok/s prefill,
~85 s per full 16K chunk, so a maxChunks=6 run is ~8.5 min PER FILE regardless
of file size (1 MB or 1 GB - you sample 6 windows). On GPU the same run is
~40 s. H-1B loads on the existing llama 5.0.3 native (granitehybrid arch, no
rebuild). Note: reading EVERY byte of a GB-scale file is not minutes on any
CPU (~135 h at this rate); raise <maxChunks> to read more (~85 s/chunk added)
or use onOversize=deterministic/sample for the repetitive bulk. Routed via the
huge-java / huge-sql rules below (priority above big-window). -->
<aiDefinition>
<key>granite-4.0-h-1b-fastchunk</key>
<modelPath>X:/Modelle/granite-4.0-h-1b-Q4_K_M.gguf</modelPath>
<contextSize>16384</contextSize>
<gpuLayers>${ai.gpuLayers}</gpuLayers>
<mainGpu>${ai.mainGpu}</mainGpu>
<devices>${ai.devices}</devices>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.2</temperature>
<threads>8</threads>
<charsPerToken>3</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<minP>0.05</minP>
<repeatPenalty>1.0</repeatPenalty>
<reasoningEffort></reasoningEffort>
</aiDefinition>
<aiDefinition>
<key>EXP-Qwen3-Coder-30B</key>
<modelPath>X:/Modelle/Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.8</topP>
<topK>20</topK>
<repeatPenalty>1.05</repeatPenalty>
</aiDefinition>
<!-- ============================================================
EXPERIMENT MODELS - batch 2 (claude2026_06_26_00)
New shortlist candidates, all context 16384. Recommended
sampling per each model card.
============================================================ -->
<aiDefinition>
<key>EXP-DeepSeek-Coder-V2-Lite</key>
<modelPath>X:/Modelle/DeepSeek-Coder-V2-Lite-Instruct-Q4_K_M.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.3</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.9</topP>
<topK>40</topK>
<repeatPenalty>1.05</repeatPenalty>
</aiDefinition>
<aiDefinition>
<key>EXP-Seed-Coder-8B</key>
<modelPath>X:/Modelle/Seed-Coder-8B-Instruct-Q4_K_M.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.3</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.9</topP>
<topK>40</topK>
<repeatPenalty>1.05</repeatPenalty>
</aiDefinition>
<aiDefinition>
<key>EXP-Granite-4.0-H-Tiny</key>
<modelPath>X:/Modelle/granite-4.0-h-tiny-Q4_K_M.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<repeatPenalty>1.0</repeatPenalty>
</aiDefinition>
<!-- Granite 4.0 H-Small (32B total / ~9B active, hybrid Mamba-2 + MoE), Unsloth
Dynamic UD-Q4_K_XL. Greedy sampling is IBM+Unsloth's official recommendation
for Granite 4 (temperature=0); no thinking mode in the 4.0 Instruct release.
Same 16384 window + 1536 output as H-Tiny for benchmark comparability. -->
<aiDefinition>
<key>EXP-Granite-4.0-H-Small</key>
<modelPath>X:/Modelle/granite-4.0-h-small-UD-Q4_K_XL.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.0</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>1.0</topP>
<topK>0</topK>
<repeatPenalty>1.0</repeatPenalty>
</aiDefinition>
<aiDefinition>
<key>EXP-Qwen3-4B-Instruct-2507</key>
<modelPath>X:/Modelle/Qwen3-4B-Instruct-2507-Q4_K_M.gguf</modelPath>
<contextSize>16384</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
<charsPerToken>4</charsPerToken>
<warnOnTrim>true</warnOnTrim>
<topP>0.8</topP>
<topK>20</topK>
<repeatPenalty>1.05</repeatPenalty>
</aiDefinition>
</aiDefinitions>
<!--
Prompt template definitions shared across all executions.
Each promptKey is referenced from fieldGenerations in the executions below.
-->
<promptDefinitions>
<promptDefinition>
<key>file-body-java</key>
<template><![CDATA[
You are a Java code indexer. Produce a dense, structured markdown summary of ONE Java source file for a searchable code index. Prioritize core logic, types, and data flow. Avoid filler words. Write in English.
## Output: start with the lead, then the sections below.
Begin with a single blockquote line - one sentence capturing what this file does in DOMAIN terms: the business/functional purpose a developer would search for (what it accomplishes), not how it is named or structured. Prefer the words a human would search ("Calculates VAT for invoices") over class mechanics ("Service class with three methods"):
> <one-sentence domain essence>
Then output these sections as markdown. Omit any section that does not apply. Use '####' for section labels. Never use '###' or higher.
#### Purpose
One or two bullets: what the type is for.
#### Type
Kind (class / interface / enum / record / annotation) and modifiers (abstract, final, sealed). extends X; implements Y; key generics and type bounds. Notable annotations (@Mojo, @Entity, Lombok, etc.).
#### Input
What comes in: constructor and method parameters, injected dependencies, consumed fields, read resources (files, buffers, streams, config).
#### Output
What comes out: return types, produced state, mutated fields, written resources, side effects.
#### Core logic
The essential steps / algorithm / responsibility as bullets. This is the most important section.
#### Public API
Each public/protected member as `name(params) -> returnType` + a clause (max 6 words) on its purpose. For a FAMILY of near-identical members (e.g. `fooN`), do not list them all: in the analysis channel enumerate and count them one per line, then in the final answer emit only the exact total and index range, e.g. `foo1..fooN (N total)`.
#### Dependencies
Imports and referenced types, as searchable names.
#### Exceptions / Errors
Notable thrown/caught exceptions, null-handling, and error conditions.
#### Concurrency
Threading, synchronization, immutability, or thread-safety notes, if any.
## Rules
- Markdown bullets and short clauses, not prose paragraphs. Sentences allowed only where a bullet would lose meaning.
- Weave class / type / domain names into the bullets so they are searchable.
- No code fences, no ```markdown / ```java, no XML tags, no formatter comments.
- COUNT EXACTLY. When you state a count of methods/fields/members, count them precisely from the source and recount before finalizing. Never round, approximate, or write "similar"/"~".
- The filename heading is already rendered above your output. Start immediately with the blockquote lead. Never produce empty output.
## Critical
If the source contains "[EOF - source was truncated]", index ONLY what is literally present. Never infer, guess, or invent any unit, field, or behavior beyond the shown source.
The file path and its full source are provided in the next (user) message: the path on the first
line, then a blank line, then the source. Index only what is literally present there.
]]></template>
</promptDefinition>
<promptDefinition>
<key>file-body-sql</key>
<template><![CDATA[
You are a SQL schema indexer. Produce a dense, structured markdown summary of ONE SQL source file (DDL/DML: tables, views, procedures, functions, triggers) for a searchable code index. Prioritize the schema shape, the tables read vs written, columns, and relationships. Avoid filler words. Write in English.
## Output: start with the lead, then the sections below.
Begin with a single blockquote line - one sentence capturing what this file does in DOMAIN terms: the business/functional purpose a developer would search for (what data it models or what operation it performs), not how it is named:
> <one-sentence domain essence>
Then output these sections as markdown. Omit any section that does not apply. Use '####' for section labels. Never use '###' or higher.
#### Purpose
One or two bullets: what this SQL object is for.
#### Type
SQL object kind: table / view / materialized view / procedure / function / trigger / index / sequence. Note the dialect if evident (PostgreSQL, MySQL, Oracle, T-SQL).
#### Schema
For tables/views: each column as `name type` plus constraints (PK, FK, NOT NULL, UNIQUE, DEFAULT, CHECK). Mark the primary key and any indexes.
#### Reads
Tables and columns this object READS from (FROM / JOIN / subquery sources, function inputs).
#### Writes
Tables and columns this object WRITES (INSERT / UPDATE / DELETE / MERGE targets, or the table a trigger fires on).
#### Relationships
Foreign keys and join relationships to other tables, as searchable `table.column -> table.column` pairs.
#### Routine logic
For procedures / functions / triggers: parameters, the essential steps, and the result or effect, as bullets.
#### Dependencies
Other tables, views, functions, or sequences referenced, as searchable names.
## Rules
- Markdown bullets and short clauses, not prose paragraphs.
- Weave table / column / constraint / domain names into the bullets so they are searchable.
- No code fences, no ```markdown / ```sql, no XML tags, no formatter comments.
- The filename heading is already rendered above your output. Start immediately with the blockquote lead. Never produce empty output.
## Critical
If the source contains "[EOF - source was truncated]", index ONLY what is literally present. Never infer, guess, or invent any table, column, or relationship beyond the shown source.
The file path and its full source are provided in the next (user) message: the path on the first
line, then a blank line, then the source. Index only what is literally present there.
]]></template>
</promptDefinition>
<promptDefinition>
<key>file-body-fallback</key>
<template><![CDATA[
You are a multi-language code indexer. Produce a dense, structured markdown summary of ONE source file (Java, C/C++, OpenCL, SQL, or similar) for a searchable code index. Prioritize core logic and data flow. Avoid filler words. Write in English.
## Output: start with the lead, then the sections below.
Begin with a single blockquote line - one sentence capturing what this file does in DOMAIN terms: the business/functional purpose a developer would search for (what it accomplishes), not how it is named or structured. Prefer the words a human would search ("Calculates VAT for invoices") over class mechanics ("Service class with three methods"):
> <one-sentence domain essence>
Then output these sections as markdown. Omit any section that does not apply. Use '####' for section labels. Never use '###' or higher.
#### Purpose
One or two bullets: what the file/unit is for.
#### Type
Kind (class / interface / enum / record / header / kernel / SQL object) and language. For OO code: extends X; implements Y; key generics. For C: header vs implementation, exported vs static. For SQL: table / view / procedure / function / trigger.
#### Input
What comes in: key parameters, consumed fields, read resources (files, buffers, streams, kernels, tables/columns, env/config).
#### Output
What comes out: return types, produced state, written resources/tables, side effects.
#### Core logic
The essential steps / algorithm / responsibility as bullets. This is the most important section.
#### Public API
Each public/exported unit as `name(params) -> returnType` + a clause (max 6 words) on its purpose. For SQL: procedures/functions with params and result.
#### Dependencies
Imports / includes / referenced modules or tables, as searchable names.
#### Exceptions / Errors
Notable thrown/handled exceptions or error conditions.
## Rules
- Markdown bullets and short clauses, not prose paragraphs. Sentences allowed only where a bullet would lose meaning.
- Weave class / type / table / domain names into the bullets so they are searchable.
- No code fences, no ```markdown / ```java / ```sql, no XML tags, no formatter comments.
- The filename heading is already rendered above your output. Start immediately with the blockquote lead. Never produce empty output.
## Critical
If the source contains "[EOF - source was truncated]", index ONLY what is literally present. Never infer, guess, or invent any unit, field, table, or behavior beyond the shown source.
The file path and its full source are provided in the next (user) message: the path on the first
line, then a blank line, then the source. Index only what is literally present there.
]]></template>
</promptDefinition>
<promptDefinition>
<key>package-body</key>
<template><![CDATA[
You are a multi-language code indexer. You receive the already-generated per-file summaries of all files in ONE package or directory (NOT raw source code). Produce one dense, structured markdown summary of the whole package for a searchable code index. Synthesize and group - do not just concatenate the file summaries. Avoid filler. Write in English.
## Output: start with the lead, then the sections below.
Begin with a single blockquote line - one sentence capturing what this package does as a whole in DOMAIN terms: the business/functional responsibility a developer would search for, not how it is named or layered:
> <one-sentence domain essence>
Then output these sections as markdown. Omit any that do not apply. Use '####' for labels. Never '###' or higher.
#### Purpose
One or two bullets: the package's overall responsibility.
#### Responsibilities
The main functional groups inside the package, as bullets. Group files by role; do not list every file separately for large packages.
#### Key units
The central classes / interfaces / modules / SQL objects and their job, one clause each, with their searchable names.
#### Data flow
How inputs move through the package to outputs, if a clear pipeline or collaboration exists across the files.
#### Dependencies
Notable internal collaborations and external modules/packages/tables the package depends on.
#### Cross-cutting
Recurring patterns across files: shared base types/interfaces, common exception/error handling, threading/concurrency notes, configuration.
## Rules
- Markdown bullets and short clauses, not prose paragraphs.
- Weave type / module / table / domain names in as searchable terms.
- Base every statement only on the provided file summaries. Do NOT invent units, methods, tables, or behavior not present in them.
- No code fences, no ```markdown, no XML tags, no formatter comments.
- The package-name heading is already rendered above your output. Start immediately with the blockquote lead. Never empty.
## Critical
If the input contains "[EOF - source was truncated]", summarize ONLY what is present. Never infer or invent files or content beyond the provided summaries.
The package path and its already-generated per-file summaries are provided in the next (user)
message: the path on the first line, then a blank line, then the summaries to synthesize.
]]></template>
</promptDefinition>
<promptDefinition>
<key>project-body</key>
<template><![CDATA[
You are writing a short overview for the very top of a project's code index. You receive the project's
per-package one-line leads (already generated, one sentence per package). Synthesize them: name the main
subsystems and how they fit together, in 2 to 4 sentences. Use domain terms a developer would search for.
No headings, no bullet lists, no code fences, no XML tags, no formatter comments. Write in English. Base
every statement only on the provided leads - never invent packages or behavior not present in them.
The index file path and the per-package one-line leads are provided in the next (user) message:
the path on the first line, then a blank line, then the leads to synthesize.
]]></template>
</promptDefinition>
<!-- ============================================================
EXPERIMENT PROMPTS v2 (claude2026_06_26_00)
Targets issues found in the v1 output: section omission on
trivial files, accessor over-enumeration, invented "keywords",
and verbosity. Selected via -Dexp.filePrompt / -Dexp.pkgPrompt.
============================================================ -->
<promptDefinition>
<key>file-body-java-v2</key>
<template><![CDATA[
You are a Java code indexer. Produce a dense, structured markdown summary of ONE Java source file for a searchable code index read by AI agents. Prioritize core logic, types, and data flow. Be terse. Write in English.
## Output
Begin with a single blockquote line - one sentence capturing what this file does in DOMAIN terms (the searchable business/functional purpose, not class mechanics):
> <one-sentence domain essence>
Then output ONLY the sections below that carry real information. OMIT any section that would be empty, "none", or "not applicable" - do not emit a heading just to say nothing. Use '####' for section labels, never '###' or higher.
TRIVIAL-FILE RULE: if the unit has no public behavior to describe (e.g. a marker/annotation, an enum that only lists constants, or a near-empty type), output ONLY the blockquote lead and a single '#### Purpose' line, and stop.
#### Purpose
One or two bullets: what the type is for.
#### Type
One line: kind (class/interface/enum/record/annotation) + modifiers; extends/implements; key generics; notable annotations (@Mojo, Lombok, etc.).
#### Input
What comes in: constructor/method parameters, injected dependencies, consumed fields, read resources.
#### Output
What comes out: return types, produced/mutated state, written resources, side effects.
#### Core logic
The essential steps/algorithm/responsibility as bullets. The most important section.
#### Public API
Each public/protected member as `name(params) -> returnType` + a <=6-word purpose clause. EXCEPTION: for plain data/config classes that are only getters/setters (e.g. Lombok beans), DO NOT list each accessor - write one line: "JavaBean getters/setters for: <comma-separated field names>".
#### Dependencies
Referenced types as searchable names. EXCLUDE this file's own type and java.lang.* .
#### Exceptions / Errors
Notable thrown/caught exceptions, null-handling, error conditions.
#### Concurrency
Threading, immutability, or thread-safety notes - only if the source actually shows them.
## Rules
- Markdown bullets and short clauses, not prose paragraphs.
- Weave class/type/domain names into the bullets so they are searchable.
- Describe ONLY what is literally in the source. NEVER invent units, fields, behavior, or concepts; in particular never mention keywords, tags, embeddings, search, or features the code does not contain.
- No code fences, no ```markdown/```java, no XML tags, no formatter comments.
- The filename heading is already rendered above your output. Start immediately with the blockquote lead. Never produce empty output.
## Critical
If the source contains "[EOF - source was truncated]", index ONLY what is literally present.
The file path and its full source are provided in the next (user) message: the path on the first
line, then a blank line, then the source. Index only what is literally present there.
]]></template>
</promptDefinition>
<promptDefinition>
<key>package-body-v2</key>
<template><![CDATA[
You are a multi-language code indexer. You receive the already-generated per-file summaries of all files in ONE package or directory (NOT raw source). Produce one dense, structured markdown summary of the whole package for a searchable code index read by AI agents. Synthesize and group - do not concatenate. Be terse. Write in English.
## Output
Begin with a single blockquote line - one sentence capturing what this package does as a whole in DOMAIN terms:
> <one-sentence domain essence>
SINGLE-CHILD RULE: if the input describes only ONE child package/file and no other content, output ONLY the blockquote lead restating that child's responsibility, and stop - emit no sections.
Otherwise output ONLY the sections below that carry real information. OMIT any that would be empty. Use '####' for labels, never '###' or higher.
#### Purpose
One or two bullets: the package's overall responsibility.
#### Responsibilities
The main functional groups inside the package, as bullets. Group files by role; do not list every file for large packages.
#### Key units
The central classes/interfaces/modules and their job, one clause each, with searchable names.
#### Data flow
How inputs move through the package to outputs, if a clear pipeline exists across the files.
#### Dependencies
Notable internal collaborations and external modules the package depends on. Focus on cross-unit/cross-package relationships, not raw JDK/Lombok imports.
#### Cross-cutting
Recurring patterns across files: shared base types, common error handling, concurrency, configuration.
## Rules
- Markdown bullets and short clauses, not prose paragraphs.
- Weave type/module/domain names in as searchable terms.
- Base every statement ONLY on the provided file summaries. NEVER invent units, methods, behavior, or concepts (in particular never mention keywords, tags, or embeddings) not present in them.
- No code fences, no ```markdown, no XML tags, no formatter comments.
- The package-name heading is already rendered above your output. Start immediately with the blockquote lead. Never empty.
## Critical
If the input contains "[EOF - source was truncated]", summarize ONLY what is present.
The package path and its already-generated per-file summaries are provided in the next (user)
message: the path on the first line, then a blank line, then the summaries to synthesize.
]]></template>
</promptDefinition>
</promptDefinitions>
</configuration>
<!--
BENCHMARK MODE (example, disabled).
The executions below use concrete production values
(gpt-oss-20B-c96k + file-body-java / package-body). To sweep
models/prompts per run instead, re-enable the
commented exp.* properties near the top of <properties> and swap the
execution values for these parameterized forms, then drive each run with
-Dexp.model / -Dexp.filePrompt / -Dexp.pkgPrompt:
<fieldGeneration>
<promptKey>${exp.filePrompt}</promptKey>
<aiDefinitionKey>${exp.model}</aiDefinitionKey>
<fileExtensions>
<fileExtension>.java</fileExtension>
</fileExtensions>
</fieldGeneration>
... (sql + fallback fieldGenerations: aiDefinitionKey ${exp.model})
ai-aggregate-packages:
<promptKey>${exp.pkgPrompt}</promptKey>
<aiDefinitionKey>${exp.model}</aiDefinitionKey>
ai-aggregate-project:
<aiDefinitionKey>${exp.model}</aiDefinitionKey>
Example invocation:
mvn prepare-package -P srcmorph-selftest -DskipTests \
-Dexp.model=EXP-Granite-4.0-H-Tiny \
-Dexp.filePrompt=file-body-java-v2 \
-Dexp.pkgPrompt=package-body-v2 \
-Dai.index.output.directory=.../src/site/ai__run1
-->
<executions>
<execution>
<id>ai-generate</id>
<phase>generate-resources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<!--
Walk both .java and .sql sources. The per-file prompt is then
chosen by extension in fieldGenerations below: .java -> the
Java-focused prompt, .sql -> the SQL-schema prompt, everything
else -> the generic fallback. (This repo is Java-only, so the
.sql/fallback entries document the capability without firing.)
-->
<fileExtensions>
<fileExtension>.java</fileExtension>
<fileExtension>.sql</fileExtension>
</fileExtensions>
<!--
Reusable fact-counter groups. Each <fact> reports its regex match count
over the WHOLE source (exact, language-agnostic structural counts the
sampled AI prose cannot reliably produce). Defined ONCE here and referenced
from rules below via <factsKey>, instead of repeating the same <facts>
block inline on the normal + huge rule for each language. Keep patterns
robust (line-anchored / unambiguous) - a fact that miscounts is worse than
none. (?m) opts into multi-line matching; (?i) case-insensitive for SQL.
-->
<factDefinitions>
<factDefinition>
<key>java-facts</key>
<facts>
<fact><label>type declarations</label><pattern>(?m)^\s*(?:public\s+|final\s+|abstract\s+|sealed\s+|non-sealed\s+|static\s+)*(?:class|interface|enum|record)\s+\w</pattern></fact>
<fact><label>public declarations</label><pattern>\bpublic\b</pattern></fact>
<fact><label>TODO/FIXME</label><pattern>\b(?:TODO|FIXME)\b</pattern></fact>
<fact><label>@Override</label><pattern>@Override\b</pattern></fact>
<!-- Structural counts validated against real OpenJDK source (see
JavaStructureFactPatternsTest). These are regex heuristics, so the labels are
honest: methods are "(approx)" (~3%, includes constructors - subtract them),
and the field count only sees fields with a STRONG modifier (final-only and
package-private fields are deliberately NOT counted, to avoid counting final
local variables). For exact structure you would need a real Java parser. -->
<fact><label>methods (approx)</label><pattern>(?m)^[ \t]*(?:(?:public|private|protected|static|final|abstract|default|synchronized|native|strictfp)[ \t]+)*(?:<[^>]+>[ \t]*)?(?!(?:if|for|while|switch|catch|return|new|else|do|try|synchronized|assert|throw)\b)[A-Za-z_$][\w$.]*(?:<[^;{}=]*>)?(?:\[\])*[ \t]+([A-Za-z_$]\w*)[ \t]*\([^;{]*\)(?:[ \t]*throws[ \t][\w$., \t]+)?[ \t]*[{;]</pattern></fact>
<fact><label>constructors</label><pattern>(?m)^[ \t]*(?:(?:public|private|protected)[ \t]+)?([A-Z][A-Za-z0-9_$]*)[ \t]*\([^;{]*\)(?:[ \t]*throws[ \t][\w$., \t]+)?[ \t]*\{</pattern></fact>
<fact><label>field declarations (w/ modifier)</label><pattern>(?m)^[ \t]*(?:(?:public|private|protected|static|transient|volatile|final)[ \t]+)*(?:public|private|protected|static|transient|volatile)[ \t]+(?:(?:public|private|protected|static|transient|volatile|final)[ \t]+)*(?!class\b|interface\b|enum\b|record\b|void\b|new\b)[A-Za-z_$][\w$.]*(?:<[^;{}=]*>)?(?:\[\])*[ \t]+([A-Za-z_$]\w*(?:[ \t]*,[ \t]*[A-Za-z_$]\w*)*)[ \t]*(?:=[^;]*)?;</pattern></fact>
</facts>
</factDefinition>
<factDefinition>
<key>sql-facts</key>
<facts>
<fact><label>INSERT rows</label><pattern>(?im)^\s*INSERT\s+INTO\b</pattern></fact>
<fact><label>tables</label><pattern>(?im)^\s*CREATE\s+TABLE\b</pattern></fact>
<fact><label>views</label><pattern>(?im)^\s*CREATE\s+(?:OR\s+REPLACE\s+)?VIEW\b</pattern></fact>
<fact><label>indexes</label><pattern>(?im)^\s*CREATE\s+(?:UNIQUE\s+)?INDEX\b</pattern></fact>
<fact><label>functions/procedures</label><pattern>(?im)^\s*CREATE\s+(?:OR\s+REPLACE\s+)?(?:FUNCTION|PROCEDURE)\b</pattern></fact>
</facts>
</factDefinition>
</factDefinitions>
<fieldGenerations>
<!-- Size-tiered routing for large files. THREE bands per source kind, by
ascending priority so the most specific (largest) wins:
plain java/sql (no priority) files up to ~275 KB -> ${ai.model}, one pass
big-window-* (priority 100) ~275 KB .. ~1 MB -> granite bigwindow, ONE 384K pass
huge-* (priority 200) > ~1 MB -> granite fastchunk, mapReduce
Why a separate huge band instead of just map-reducing on the big window?
Prefill is O(n^2) in prompt length, so ONE big 384K pass over a multi-MB file
is catastrophically slow, and map-reducing AT the big window (6 x 384K passes)
is worse still. The fast path is the opposite: chunk with a SMALL window
(granite-4.0-h-1b-fastchunk, 16K) so each prefill is cheap, and cap
<maxChunks> so a 7 MB file stays a handful of calls (~1 h order on the
reference CPU; less on GPU) - sampling a representative head/tail/spread, which
is the right trade-off for repetitive data needing no precise whole-file read.
Each band has its own prompt (file-body-java / file-body-sql). Without the
big-window/huge rules a file larger than ${ai.model}'s window hard-fails the
build (the plugin never auto-selects a model) - these rules are how YOU satisfy
that check. Default onOversize=fail still aborts any rule that does not opt into
sample/mapReduce/deterministic. Thresholds are conservative; tune to your models. -->
<fieldGeneration>
<id>huge-java</id>
<promptKey>file-body-java</promptKey>
<aiDefinitionKey>granite-4.0-h-1b-fastchunk</aiDefinitionKey>
<priority>200</priority>
<!-- Map-reduce on a SMALL fast window: chunk at line boundaries, summarize each,
then combine. maxChunks bounds the run time to ~60-90 min/file by sampling a
representative subset (head + tail + evenly spaced). Alternatives for pure
data: sample (head only, one call) or deterministic (no model, instant). -->
<onOversize>mapReduce</onOversize>
<maxChunks>6</maxChunks>
<factsKey>java-facts</factsKey>
<condition>
<and>
<conditions>
<condition>
<extensions><extension>.java</extension></extensions>
</condition>
<condition>
<size><min>1000000</min></size>
</condition>
</conditions>
</and>
</condition>
</fieldGeneration>
<fieldGeneration>
<id>huge-sql</id>
<promptKey>file-body-sql</promptKey>
<aiDefinitionKey>granite-4.0-h-1b-fastchunk</aiDefinitionKey>
<priority>200</priority>
<onOversize>mapReduce</onOversize>
<maxChunks>6</maxChunks>
<!-- Deterministic, EXACT whole-file counts prepended to the AI body. The
sampled map-reduce prose can't count reliably (no call sees the whole
file), so each <fact> reports its regex match count over the FULL
source. Fully generic/language-agnostic - the meaning is in the regex,
so the same mechanism counts INSERT rows here or `\bboolean\b` fields
in Java. Multi-line matching is opt-in via the inline (?m) flag. -->
<factsKey>sql-facts</factsKey>
<condition>
<and>
<conditions>
<condition>
<extensions><extension>.sql</extension></extensions>
</condition>
<condition>
<size><min>1000000</min></size>
</condition>
</conditions>
</and>
</condition>
</fieldGeneration>
<fieldGeneration>
<id>big-window-java</id>
<promptKey>file-body-java</promptKey>
<aiDefinitionKey>granite-4.0-h-tiny-bigwindow</aiDefinitionKey>
<priority>100</priority>
<!-- ~275 KB .. ~1 MB: fits Granite's 384K window, summarized in ONE pass
(fast on GPU). Files > ~1 MB are caught by huge-java above (priority 200),
so this rule never needs to handle the oversize case; default
onOversize=fail is the safe floor if the huge rule is removed. -->
<condition>
<and>
<conditions>
<condition>
<extensions><extension>.java</extension></extensions>
</condition>
<condition>
<size><min>275000</min></size>
</condition>
</conditions>
</and>
</condition>
</fieldGeneration>
<fieldGeneration>
<id>big-window-sql</id>
<promptKey>file-body-sql</promptKey>
<aiDefinitionKey>granite-4.0-h-tiny-bigwindow</aiDefinitionKey>
<priority>100</priority>
<condition>
<and>
<conditions>
<condition>
<extensions><extension>.sql</extension></extensions>
</condition>
<condition>
<size><min>275000</min></size>
</condition>
</conditions>
</and>
</condition>
</fieldGeneration>
<fieldGeneration>
<id>java</id>
<promptKey>file-body-java</promptKey>
<aiDefinitionKey>${ai.model}</aiDefinitionKey>
<!-- Exact, whole-file structural counts prepended to EVERY Java summary (not just
oversize files), giving downstream agents authoritative numbers the prose need
not restate. Shared, defined once in <factDefinitions> above and referenced by
key here (and by huge-java) instead of repeating the block inline. -->
<factsKey>java-facts</factsKey>
<condition>
<extensions><extension>.java</extension></extensions>
</condition>
</fieldGeneration>
<fieldGeneration>
<id>sql</id>
<promptKey>file-body-sql</promptKey>
<aiDefinitionKey>${ai.model}</aiDefinitionKey>
<factsKey>sql-facts</factsKey>
<condition>
<extensions><extension>.sql</extension></extensions>
</condition>
</fieldGeneration>
<!-- Explicit fallback: applies to any file no rule above matched.
Exactly one fallback is allowed; without it an unmatched file
fails the build (see AiFieldGenerationSelector). -->
<fieldGeneration>
<id>fallback</id>
<promptKey>file-body-fallback</promptKey>
<aiDefinitionKey>${ai.model}</aiDefinitionKey>
<fallback>true</fallback>
</fieldGeneration>
</fieldGenerations>
</configuration>
</execution>
<execution>
<id>ai-aggregate-packages</id>
<phase>process-resources</phase>
<goals>
<goal>aggregate-packages</goal>
</goals>
<configuration>
<fieldGenerations>
<fieldGeneration>
<promptKey>package-body</promptKey>
<aiDefinitionKey>${ai.model}</aiDefinitionKey>
</fieldGeneration>
</fieldGenerations>
</configuration>
</execution>
<!--
Phase 3 - project index. Harvests the per-package lead already produced by
aggregate-packages into a single project.ai.md. Bound to prepare-package so it
runs after process-resources (aggregate-packages).
The per-package listing is deterministic (no model). The optional project
overview paragraph below is opt-in: the single <fieldGeneration> enables ONE
extra AI call that writes a short #### Overview from the package leads. Remove
the <configuration> block to fall back to the purely deterministic index.
-->
<execution>
<id>ai-aggregate-project</id>
<phase>prepare-package</phase>
<goals>
<goal>aggregate-project</goal>
</goals>
<configuration>
<fieldGenerations>
<fieldGeneration>
<promptKey>project-body</promptKey>
<aiDefinitionKey>${ai.model}</aiDefinitionKey>
</fieldGeneration>
</fieldGenerations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>vmlens</id>
<build>
<plugins>
<plugin>
<groupId>com.vmlens</groupId>
<artifactId>vmlens-maven-plugin</artifactId>
<configuration>
<!--
Staged scope (one class for now): run vmlens interleaving
analysis only on the minimal smoke test. The `com.vmlens:api`
test dependency lives in the main <dependencies> block.
Expand <includes> as more concurrency tests are added (the
streambuffer repo runs vmlens over its whole suite).
-->
<includes>
<include>**/VmlensInterleavingSmokeTest.java</include>
</includes>
</configuration>
<executions>
<execution>
<id>vmlens-test</id>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>jcstress</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>jcstress</id>
<phase>test</phase>
<goals><goal>exec</goal></goals>
<configuration>
<executable>${java.home}/bin/java</executable>
<classpathScope>test</classpathScope>
<arguments>
<argument>-classpath</argument>
<classpath/>
<argument>org.openjdk.jcstress.Main</argument>
<argument>-v</argument>
<argument>-m</argument>
<argument>default</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>