STIG Help

Running the build & Gradle caching

How to invoke the build from a consumer project (e.g. stig-project), and the caching rules that keep it both fast and correct.

Just run it plainly

./gradlew :activities:<element>:stigGenerateHtml

No flags for day-to-day work. Caching on, configuration-cache on, daemon on, file-system watching on. A normal incremental build reuses cached task outputs (the expensive stigAnalysisP6RunAnalyzer especially) and still picks up source and engine/plugin code changes.

File and dependency rules

Declare consumed files as file inputs, produced artifacts as outputs, and effective settings as value inputs; a pathname inside an @Input object does not track file contents. Connect generated inputs to their producers' output providers: Gradle finishes dependencies before checking each consumer's inputs, and identical output content permits downstream reuse. Read task data during execution and track configuration-time reads separately; unrelated tasks must not require it, so MkDocs configuration is needed only for export. Keep external files stable during a build: Gradle may reuse fingerprints and does not automatically lock files or provide immutable copies. Configuration-cache reuse, up-to-date checks and build-cache restoration are separate decisions; disabling the build cache still allows up-to-date skips. Cheap path validation and requests for current diagnostic evidence run every time, while unchanged compilation and analysis remain reusable. See Gradle's incremental build and configuration-cache requirements.

Intended invalidation contract

There are two independent concerns: changes to consumer inputs and changes to STIG's implementation. In both cases, the unit of reuse is an activity's stage and its consumed artifacts. A root aggregate schedules its dependencies; it does not require every dependency to execute. A producer that executes again but writes identical consumed output should leave its downstream consumer up to date.

Status: native producer input isolation, partial source/header compilation reuse and separation of raw compilation from LLVM processing are implemented. P3/P5 compilation, linking, preparation and final transformations now execute in separate engines. The production P5 implementation-mutation regression preserves both raw compiler tasks and earlier linking. The remaining pipeline, including P6 and reporting, still needs extraction. The typed P5 transformation adapter also still shares the project plugin classpath; its engine is isolated, but configurator-only changes can still invalidate that adapter. See the workplan for current verification and consumer acceptance.

Logging and partial-result observation actions now live in stig-gradle-execution. Their frontend service uses a stable observer interface, so changing unrelated plugin code does not change the compiler/link tasks' additional action fingerprints. The production mutation test changes a real help-action diagnostic, observes the new output, and requires both compiler tasks and both link tasks to remain up to date with zero Clang launches.

Change

Required work

Work that should remain reusable

No relevant change

P1 asks Bazel to check its actions; shared native installation is verified

Compilation, native executions, metrics, rendering

Source/private header of activity A

Dependent units of A, affected metrics/descriptions, then consumers of changed artifacts

Independent units and activities; PhASAR/analyzer executables

Header or source genuinely shared by A and B

Dependent units in both activities

Activities without that dependency

A's source selection or harness/stub sources

A's selection, affected compiler invocations, linking/transforms and downstream consumers

Native target compilation and unrelated activities, unless the patch changes their native inputs

A's semantic rewrite rule

A's affected transformations, optimization/linking and consumers of changed LLVM

Raw Clang outputs, P1/P2 and unrelated activities when their effective inputs are unchanged

Rewrite introduces a replacement source or different compiler flags

Affected source compilation as well as transforms

Independent compiler invocations

Rewrite review status or explanation only

Current validation, review evidence and reports

Raw compilation and native analysis when their effective commands/modules are unchanged; a failed validation must still block acceptance

ASIL annotations, sources/sinks or analyzer options

Interface/run-plan generation and affected native runs

Raw compilation unless those values also change the generated harness or compiler inputs

Metrics algorithm

Metrics and their report consumers

LLVM compilation and native data-flow analysis

HTML/template/diagram presentation only

Affected reporting

Compilation, native executions and unchanged metric collection

build.gradle.kts edit

Reconfiguration; stages whose resolved values/files changed

Stages with identical effective inputs; the whole script is not a compilation input

Analysis-configuration regeneration

Consumers of the generated artifacts that actually changed

Expensive stages when regeneration produced the same effective configuration

PhASAR source/build/toolchain change

PhASAR production, dependent native analyzer production and affected native runs

Activity LLVM if its own LLVM/compiler inputs are unchanged

Analyzer C++ change

Native analyzer production and affected native runs

PhASAR production and activity LLVM

Compilation/transform/execution engine change

The changed engine's stage and consumers of changed results

Stages outside its implementation and artifact dependency graph

Published selection changes

Validate the release's selected component identities and pins, then rebuild affected components

Unchanged components once their complete identity/input checks pass

Shared root DSL settings affect every activity that inherits them. Changing a shared rule affects the activities whose resolved rule set uses it. A comment-only source edit may change source descriptions without changing the native executable. The executable's hash is therefore not a substitute for the Bazel action/input inventory.

Implementation boundaries

Gradle fingerprints a custom task's implementation and its classloader hierarchy. Moving task classes into separate JARs but loading those JARs together on the same plugin classpath does not isolate them. Nor does a dependsOn edge by itself fingerprint the predecessor's implementation: the edge establishes execution order, and explicitly declared input artifacts establish data dependencies. See Gradle's incremental build model.

The effective reuse boundary is the task's implementation classpath and its declared execution classpath, including transitive runtime dependencies. Gradle does not inspect which Kotlin classes or methods an invocation actually calls. Changing a shared runtime library can invalidate every engine using it. Kotlin incremental compilation, which may recompile fewer source files, does not provide task-execution isolation.

Proposed module map, version 2 (2026-10-01)

This proposal supersedes version 1's use of stig-stage-* for reusable execution engines. Compilation and linking are operations used in multiple pipeline stages. The revised structure distinguishes three things:

Concept

Responsibility

Ownership and reuse

Pipeline stage

Names a part of the workflow and configures its tasks, dependencies, outputs and readiness checks

One stage owns each pipeline task instance

Gradle task instance

Performs one configured operation and owns particular outputs

May supply several consumers, including tasks in later stages; is not registered again for each consumer

Execution engine

Implements compilation, transformation, metrics or another operation

Reused by separate task instances in different stages, with separate inputs and outputs

stig-gradle-plugin remains the consumer entry point and automatically configures the internal stage plugins. Both levels contain configuration, not analysis algorithms. They can still be written in Kotlin or the Kotlin DSL; "configuration only" does not mean that there are no Kotlin source files. Consumers continue applying the existing plugin IDs. Engine implementations are resolved as individual task execution inputs, outside the configurators' runtime classpath.

The following stages follow the major groups in the documented task and artifact flow. The diagram records September 11 wiring; newer raw-compiler tasks belong with their existing module-building consumers. These stage numbers are proposed architecture labels, not renames of existing task paths or artifact identities. Numbered stage configuration modules remain proposed. The LLVM execution engines and task adapters listed in "Current extraction" below are implemented; other operation engines remain proposed.

Directory / proposed stage module

Tasks owned by the stage

Existing workflow mapping

stages/stig-gradle-stage-01-source-preparation

Native-source patches, Bazel build/action discovery, captured source/header inputs, native compiler commands and LLVM command conversion

P1–P2

stages/stig-gradle-stage-02-original-evidence

Select implementation/reference units, compile/link the original-definition evidence and full original LLVM inventory, discover compiled interfaces

P3–P4, original inventory and interface discovery

stages/stig-gradle-stage-03-analysis-input

Generate harness, select analysis/support sources, compile/link analysis input and configured inventory, derive read-only configuration/review evidence, apply transformations, validate symbols/contracts, derive endpoints and run plans

P5, configured inventory and transform-review preparation

stages/stig-gradle-stage-04-native-analysis

Select or create per-run LLVM slices, execute native analyses, validate and retain their results

P6

stages/stig-gradle-stage-05-analysis-evidence

Select sources for enrichment, collect metrics/descriptions, join applied transformations to results and generate analysis diagrams/evidence

P7

stages/stig-gradle-stage-06-report

Wire specification compilation/checking, assemble Markdown/appendices/statistics, run Dokka and validate the HTML report

Model validation and final report generation

A stage aggregate represents completion of that stage's required tasks, including valid reused outputs. Stage numbers do not introduce a global barrier between activities. Preserve actual artifact dependencies: original compilation and implementation-unit selection can overlap; metrics/descriptions can start from selected compilation commands before native analysis finishes. Making every later-stage task wait for every earlier-stage task would discard that documented concurrency. Add a readiness gate where correctness requires it, not merely because a task has a larger stage number.

Keep reusable Kotlin execution modules at the repository root, alongside the other Kotlin modules. Leave their names unnumbered because an engine can serve more than one stage. These contain ordinary Kotlin processing code, not Gradle task registration. A module groups a coherent operation family rather than one class or one function; an engines/ parent directory is not needed to preserve that responsibility boundary.

Directory / proposed engine module

Executable responsibility

Stage users

stig-engine-native-inputs

Bazel invocation/action discovery, source capture and compiler-command conversion

01

stig-engine-llvm-compile

Raw Clang compilation, depfiles, per-unit reuse and completed-compilation evidence

02, 03

stig-engine-llvm-link

Link, disassemble and verify explicit bitcode inputs/pass recipes; no rewrite-rule interpretation

02, 03

stig-engine-analysis-config

Source selection, provenance/interface inspection, harness/endpoint/run-plan generation and configuration/review derivation

02, 03; explicit analysis configuration commands

stig-engine-llvm-transform

Replacement definitions, rewriting/conversion, inlining/optimization decisions and transformation/function-contract validation

03

stig-engine-analyze

Slicing, native process execution, per-run reuse, diagnostics and result validation

04

stig-engine-source-info

Source-code metrics and API/function descriptions

05

stig-engine-diagrams

Analysis diagram generation and applied-transformation presentation

05

stig-engine-model

Model loading/checking, format import/export and explicit model/scaffold generation

06; explicit model commands

stig-engine-report

Markdown/appendices/statistics presentation, HTML/viewer assets and STIG's Dokka extension

06

The separate diagram engine keeps an HTML implementation edit from invalidating earlier diagram generation. The configuration engine initially groups related selection/generation operations: a change there can rerun its other users, but identical generated bytes must preserve compilation and native execution. Split an engine further only when dependencies or measured cost justify it. Reuse of one compiler engine does not imply reuse of the same compiled outputs: original-reference and analysis-input tasks have their own source selections, flags and outputs.

For example, stage 02 owns the task compiling original definitions; stage 03 owns another task compiling analysis input. Both resolve stig-engine-llvm-compile. Stage 03 additionally owns transformation tasks resolving stig-engine-llvm-transform. A transformation implementation edit must preserve both raw compiler tasks and the original-reference linker. Changing the shared compiler implementation legitimately invalidates both compiler users.

Foundation module/build

Intended contents after extraction

stig-gradle-plugin

Public project plugin entry point and DSL, stage composition, effective configuration/artifact resolution, and configuration of standalone lifecycle commands

stig-gradle-settings-plugin

Existing settings plugin ID, invocation/configuration-access coordination and loading the narrow LLVM task adapters; no transformation implementation or project-stage dependency

stig-gradle-execution

Shared Gradle adapter: declared inputs/outputs, InputChanges, Java toolchain selection, engine invocation and Gradle logging

stig-execution-api

Gradle-independent request/change protocol, event records/reporting and atomic file/lease support

stig-core

Metamodels, domain types and model rules; no stage, rendering or Gradle dependencies

stig-engine

Minimal shared process/file utilities, diagnostics and artifact contracts; no stage/engine dependencies and no blanket api(stig-core)

stig-code-analyzer

Native C++ analyzer and Kotlin build/package/install orchestration, independent of JVM stage/report implementation

stig-docs

Authored documentation, examples, glossary and workplans

stig-idea-plugin

IDE integration and inspections using explicit model/contracts dependencies

stig-codex-plugin

Skills, references and distribution packaging

build-logic

Included build for building STIG itself: JVM conventions, packaging/publication recipes, Node workspace coordination and architecture tests

build-logic is built before the main STIG modules and is not an analysis engine or another consumer entry point. Its conventions must be available while compiling stig-gradle-plugin; placing them inside that plugin would create a bootstrap dependency cycle. Keep repository build support here and consumer analysis execution in the task-adapter modules under tasks/ and the reusable execution modules at the repository root.

Current extraction (2026-10-01)

The six LLVM engine directories moved to the repository root on 2026-10-14. Their Gradle project IDs, publication coordinates, Kotlin packages, and execution responsibilities remain unchanged.

Module / directory

Current responsibility

stig-gradle-execution

Stable Gradle engine adapter and task-observation actions; frontend logging and evidence-attribution services implement its observer interface

tasks/stig-gradle-tasks-llvm

Typed raw-compiler and module/link tasks, their declared inputs/outputs and request serialization; loaded through the settings plugin

tasks/stig-gradle-tasks-llvm-transform

Existing typed P5 transformation task, declared inputs/outputs and request serialization

stig-engine-llvm-common

Compile-command/snapshot contracts, toolchain policy and common native process support; no model or rewrite implementation

stig-engine-llvm-compile

Raw compiler execution, dependency validation and per-unit reuse

stig-engine-llvm-link

Copy raw outputs into owned preparation outputs, link and validate original LLVM; no rewrite-rule implementation

stig-engine-llvm-rewrite

Shared pre/post-link rewrite algorithms and compiler-transform policy

stig-engine-llvm-prepare

Pre-link rewriting, optimization and analysis-input linking; uses the shared linker and rewrite engines

stig-engine-llvm-transform

Final P5 transformations, validation and diagnostic evidence; does not depend on the preparation engine

stig-llvm-contracts

LLVM transform/report/observation data crossing module boundaries; no execution implementation

The separate preparation and final-transformation artifacts let a final P5 implementation edit preserve P5 linking as well as P3 and raw compilation. Both transformation engines still depend on legacy stig-engine code; reducing that shared dependency belongs to the subsequent pipeline extraction. Compiler and original-linker execution do not depend on stig-engine, stig-core or the transformation engines.

The project plugin resolves four execution configurations: stigLlvmCompileEngineRuntimeClasspath, stigLlvmLinkEngineRuntimeClasspath, stigLlvmPrepareEngineRuntimeClasspath and stigLlvmTransformEngineRuntimeClasspath. Their artifacts are task @Classpath inputs, not plugin runtime dependencies. Local composite substitution selects the working-tree modules; published dependencies select the engine version belonging to the loaded STIG plugin. Existing published selection, verification and PhASAR pin checks remain additional to content/recipe/toolchain checks.

DSL-to-LLVM contract tests remain with the project plugin and use test-only engine dependencies. This keeps the production runtime boundary intact while exercising the public configuration through actual LLVM transformations.

Keep the stig- artifact prefix: published coordinates and IDE module lists remain unambiguous. Normal Kotlin packages remain independent of directory grouping. Root module directories use their existing Gradle project names; any explicit grouping in settings must preserve those names and publication coordinates. A folder move must not silently rename a published artifact or introduce another runtime module.

Standalone import/update/scaffolding commands and the native tool producer are outside the automatic per-activity stage sequence. In particular, model import remains an explicit source-editing invocation; report generation must not start editing authored source merely because model execution code has moved. The root HTML aggregate consumes the enabled activities' report tasks. Native tool production retains its own content/toolchain/pin validity checks.

What a change invalidates

Controlled change

Required execution behavior

Stage/plugin configuration implementation changes, resolved task inputs stay identical

Reconfiguration can occur; processing tasks remain reusable

Stage configuration changes one task's selected files, flags or other effective inputs

That task is reconsidered; only affected compilation units execute, and consumers follow changed artifacts

One engine implementation changes

Task instances using that engine are reconsidered; unrelated engines remain reusable

A shared runtime library changes

Its actual users are reconsidered; there is no class/method-level reachability exemption

Producer executes but writes identical consumed files

Consumers with otherwise unchanged inputs remain reusable

Therefore, changing anything in a stage module does not inherently mean that every task of that stage must run. It would become broad invalidation if the stage implementation were also part of every task's execution classpath. Keeping configuration and execution separate is the essential constraint, not simply adding more Kotlin modules. Do not add stage-defined doFirst/doLast processing actions that reconnect task execution to the broad configurator classpath. Several stage configuration plugins may share a configuration classpath; that classpath must not become the implementation classpath of the expensive processing tasks.

Artifact consumers do not load the producer engine: transformation reads original provenance files, reports read analysis evidence, and the plugin wires their providers. Engine-specific schemas stay with their owner. If a typed contract must cross a boundary, extract only that contract instead of taking a dependency on the implementation JAR. Keep metamodel dependencies explicit in domain engines; the raw compiler need not load the complete model/rule set. Do not put every request or DSL type into the common runtime merely to make imports compile. Code moves out of both the current Gradle plugin and the current engine into its owning execution engine; PhASAR remains independent.

The tested prototype uses Gradle's built-in JavaExec tasks, explicitly declared input/output files and separate engine classpaths. A changed configurator that supplies the same task properties leaves engine executions up to date. A configurator change that supplies different compiler arguments correctly invalidates compilation. A worker-based implementation must satisfy the same contract: worker isolation alone does not change the enclosing task's implementation fingerprint. No reflective classloader manipulation, ignored implementation hashes or hand-maintained semantic-version flags are part of this proposal.

The incremental runner prototype now uses StigIncrementalEngineTask from stig-gradle-execution, loaded through the settings classpath before project-stage configuration. Its engine is a separately declared @Classpath input, executed in a Java process. Gradle decides whether execution is incremental and supplies the changed files; the adapter passes that decision and those changes through stig-execution-api. There is no second freshness decision that could override Gradle's forced execution or output-integrity checks.

The adapter's physical TestKit fixture verifies unchanged and configuration-only reuse, added/modified/removed files, non-incremental recipe and engine changes, changed effective parameters, task-local --rerun, configuration cache reuse, damaged output repair, build cache restoration and engine failure propagation. This uses the actual adapter and a small fixture engine; it does not establish that the production compiler preserves all its existing dependency checks, diagnostics or workspace leases after migration. Those remain production acceptance checks.

The parent classpath must also stay narrow. ai.exida.stig-settings is now published from stig-gradle-settings-plugin, while ai.exida.stig remains in stig-gradle-plugin. Previously both IDs came from the broad project-plugin artifact, which defeated isolation even when task classes lived in separate JARs. The settings extraction retains the public plugin ID and configuration-access coordination. Keep project stages, execution engines and their broad dependencies off that parent classpath. Separate settings and project plugin artifacts must work with both local composite selection and published plugin markers. A change to the adapter or its actual parent runtime dependencies legitimately invalidates tasks using it; this proposal does not ignore those implementation changes.

StigStageIsolationTest contains both controls: changing project configuration preserves a task loaded from the parent runner classpath, while putting unrelated implementation on that parent classpath invalidates the same task. Before migrating compilation, preserve per-unit dependency validation, workspace leases, event/problem reporting and forced execution in production fixtures. Moving code to a worker or a separate JAR without verifying these classpath boundaries is insufficient.

Raw compilation now belongs to StigCompileLlvmBitcodeTask. StigBuildLlvmModuleTask consumes its raw bitcode and source index, applies transformations to separate copies, optimizes and links. LLVM-only rule edits no longer invalidate the compiler producer. The checkpoint before optimization, current rule validation and original-source provenance remain required; raw compiler outputs must not be modified by transformation tasks.

P3 uses stigAnalysisP3CompileProvenanceSources before the existing stigAnalysisP3BuildProvenanceBitcode. P5 uses stigAnalysisP5CompileAnalyzerInputSources before stigAnalysisP5BuildUntransformedAnalyzerInput. The full ownership and configured analyzer-input inventories have equivalent separate compiler producers. Existing module, raw bitcode and compilation-log artifact paths are retained, with one task owning each output. To force Clang execution explicitly, target the compiler task with task-local --rerun; forcing only the linked module task does not force its unchanged compiler prerequisite.

Every raw compilation retains Clang's dependency file beside its bitcode, including authored sources without a native-input snapshot. On an incremental invocation, changed source/header contents invalidate the units whose dependencies include those paths. Missing or empty dependency evidence cannot authorize reuse. Added/removed headers and changed include mappings conservatively invalidate the compilation scope because a previous depfile does not record failed include lookups or __has_include results. Compiler/toolchain/policy changes and incomplete native-input evidence still require full recompilation within that task.

The plugin declares authored harness/stub header files individually, preserving absolute path-to-content identity without treating their ancestor directory as an input. This avoids accidental dependencies on task outputs below the activity directory. Partial-analysis input-recording hooks are registered consistently; enabling analysis must not alter the task-action identity of an otherwise unchanged compiler.

stigPrepareAnalysisTransformConfiguration materializes each activity's complete resolved transform configuration, including reasons and review state. P6 declares this artifact as an incremental file input and validates the current rules before deciding whether native results can be reused. A review-only edit therefore refreshes validation and provisional_analysis.json while retaining executions with identical modules, analyzer configurations and commands. The input is not filtered or omitted. Changed LLVM or native run inputs still invalidate the affected executions; contradictory current evidence still fails validation. Captured transformed-checkpoint execution does not depend on this local configuration producer.

This separation handles rule inputs. The execution-engine extraction additionally protects raw compilation and original linking from P5 implementation changes. The production regression changes a literal in the real final-P5 engine class, observes the changed diagnostic, and requires zero Clang launches, unchanged prior artifacts and UP-TO-DATE outcomes for both compiler tasks and both earlier link tasks. Unchanged and identical-byte relocation controls prevent a stale implementation from falsely satisfying the test.

Published-mode reuse also needs component identity to be distinguished from report identity. Today the native analyzer embeds stigAnalyzerVersion, derived from the overall STIG version. A report-only release can therefore invalidate native production independently of the classpath issue. The proposed release mapping selects a native component identity plus its LLVM/PhASAR pins; the report records the consuming STIG release separately. Published selection/pin verification remains additional to content, recipe and toolchain verification. Do not remove the current version checks before replacing them with that explicit, tested mapping.

Verification and migration order

Start with a bounded activity-input regression gate and straightforward input-declaration fixes, then proceed to the execution refactor. Do not postpone the expensive-stage isolation until every possible input optimization is finished. Separating and extracting raw compilation is one migration step, addressing both kinds of invalidation.

  1. Extend the real two-activity fixtures with DSL/report-only edits, rule-only edits, review-only edits and unchanged configuration regeneration. Specifically edit an existing project-level registry rule selected by A but not B; A's effective transform configuration must change and B's must not. Also cover an unused registry rule and a genuinely shared rule/default, for which all actual consumers must invalidate. Assert both task outcomes and compiler/analyzer invocation counts. Fix whole-script/whole-registry inputs where a stage only consumes resolved activity-specific values; global validation and project reports can still refresh. Existing NativeCompilationInputSnapshotFunctionalTest already checks private source/header edits leave the other activity up to date; StigIncrementalCompilationFunctionalTest checks per-unit reuse and invalidation.

  2. Extract the separate raw compilation producer as the first isolated production engine. Assert rule edits preserve raw compiler output bytes and modification times while changing the transformed LLVM as expected. Added sources/changed flags must still compile. Missing/corrupt outputs must rebuild or restore verified cache entries.

  3. Migrate LLVM preparation and native analysis execution onto isolated engine classpaths next, followed by native-input preparation and metrics/reporting. Port the fixture's mutation cases to the production task wiring as each boundary moves. Preserve task names, original-source links, snapshot/concurrency ownership and current failure reporting. Move one producer at a time, with one authoritative execution path. For each stage, test the resolved runtime dependency graph so an accidental dependency on a reporting or later-stage engine cannot silently restore the broad invalidation. Preserve successful gates as subsequent stages move; avoid repeated full product rebuilds.

  4. Separate native component and report identities for published updates, with tests for identical native inputs across two STIG releases, changed component bytes under the same release, changed pins and mismatched identities.

  5. Verify the four-activity consumer once after migration, then check an unchanged repeat, a report implementation edit and a rule edit in one activity. Keep these real compiler/analyzer probes in the explicit integration gate; the small Gradle fixtures belong in normal checks.

The compiler-free build-logic:StigStageIsolationTest contains 20 architecture cases: unchanged execution, configurator-only bytecode, each independent engine, shared engine dependency, source/compiler/native analyzer/ endpoint/template inputs, changed arguments from the configurator, unchanged producer outputs, ordering-only dependencies, the shared-classpath counterexample, cache restoration and explicit reruns. It compiles actual fixture JARs and checks native-work stand-in invocations rather than merely editing unrelated text files. StigNativeBuildInputsTest uses the production native input declarations in both local and published modes, covering source, scripts, toolchain, version and additive pin checks. These tests establish the boundary contract; they do not replace production wiring tests or prove that every existing task already satisfies it.

Every stage must declare the files it reads, effective configuration, engine/runtime dependencies and applicable toolchain/selection identity. Validate required inputs before launching a tool and validate schema, selected scope, tool identity and output completeness before publishing a successful artifact. Configuration-cache reuse, normal up-to-date reuse, build-cache restoration and explicit reruns must retain these same correctness rules.

The settings (in stig-project/gradle.properties)

Property

Value

Why

org.gradle.caching

true

Reuse task outputs across builds — keep it.

org.gradle.configuration-cache

true

Cache the task graph/config — keep it.

org.gradle.configuration-cache.problems

fail

Reject new configuration-cache violations in checked builds.

org.gradle.vfs.watch

true

Enables efficient input watching and --continuous.

The STIG tool repository sets configuration-cache problem handling to fail, so release verification cannot pass after discarding a cache entry because a task captured a Gradle script or accessed Project during execution. Consumer projects should use the same setting when configuration-cache compatibility is part of their checked build contract.

Native analyzer output and VFS watching

stigAnalysisP6RunAnalyzer runs the native analyzer in a detached systemd-run --user --scope subprocess when a memory limit is configured. External writes directly into a declared Gradle output directory are unsafe with VFS watching because Gradle can retain an incomplete watched snapshot.

P6 therefore rewrites each run-plan outDir and --out path to a task-private staging directory. It validates and normalizes the staged results, then publishes the tree into its declared @OutputDirectory with Gradle FileSystemOperations. The publication also runs on failure so analyzer logs and structured problem reports remain available. This makes VFS watching, up-to-date checks, build-cache storage/restoration, and downstream P7 consumption use the same complete published tree.

org.gradle.vfs.watch is a Gradle start parameter loaded from gradle.properties for each invocation. The next build uses a changed value; stopping the daemon is not normally required.

clean, rm, --rerun-tasks, --stop

  • ./gradlew clean (or rm -rf build/) — safe. Removes all outputs; the next build re-runs each task or restores it from the build cache (so a clean build is often still fast — P6 restores from cache when its inputs are unchanged, and only re-analyzes when they actually changed). Use for a guaranteed-fresh tree.

  • --rerun-tasks — forces execution of the selected task graph, bypassing up-to-date and build-cache reuse. Prefer a task-local <task> --rerun for a focused timing or regeneration check. Re-running P6 costs roughly the analyzer's runtime; unchanged outputs do not by themselves require downstream tasks to execute.

  • ./gradlew --stop — only if you suspect a stale daemon after editing the included ../stig build and a normal build is not reflecting it.

  • Deleting or changing a declared output invalidates that task's up-to-date state; Gradle reruns it or restores a matching build-cache entry. An UP-TO-DATE task with missing required output indicates a declaration or producer bug to fix. Prefer a task-local --rerun when deliberately requesting fresh execution.

After editing ../stig (engine/plugin) code

With stigSource=local, a normal ./gradlew … build recompiles the included build and re-runs the affected rendering tasks. Published mode ignores the sibling checkout. If you ever doubt a change took effect, inspect the task outcome and its declared implementation/input changes before forcing a rerun.

Investigating Gradle deprecations

Use --warning-mode all -Dorg.gradle.deprecation.trace=true --console=plain --info on the affected command. The first caller outside Gradle identifies whether STIG or an upstream plugin owns the deprecated API use. Keep dependency verification enabled during this investigation.

With Gradle 9.8.0, Dokka 2.2.0 and Kover 0.9.11 call the deprecated Configuration.setVisible(boolean) method during project configuration. The traces identify Dokka's GradleUtilsKt and Kover's PrepareKoverKt, AbstractVariantArtifacts, and ConfigurationsKt. The detailed warning schedules removal in Gradle 11; the generic build footer alone does not identify the affected API or its owner. This warning remains visible until those plugins stop calling the method. Recheck the Dokka releases and Kover releases when updating them.

23 October 2026