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
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 |
| 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 |
|---|---|---|
| Native-source patches, Bazel build/action discovery, captured source/header inputs, native compiler commands and LLVM command conversion | P1–P2 |
| 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 |
| 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 |
| Select or create per-run LLVM slices, execute native analyses, validate and retain their results | P6 |
| Select sources for enrichment, collect metrics/descriptions, join applied transformations to results and generate analysis diagrams/evidence | P7 |
| 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 |
|---|---|---|
| Bazel invocation/action discovery, source capture and compiler-command conversion | 01 |
| Raw Clang compilation, depfiles, per-unit reuse and completed-compilation evidence | 02, 03 |
| Link, disassemble and verify explicit bitcode inputs/pass recipes; no rewrite-rule interpretation | 02, 03 |
| Source selection, provenance/interface inspection, harness/endpoint/run-plan generation and configuration/review derivation | 02, 03; explicit analysis configuration commands |
| Replacement definitions, rewriting/conversion, inlining/optimization decisions and transformation/function-contract validation | 03 |
| Slicing, native process execution, per-run reuse, diagnostics and result validation | 04 |
| Source-code metrics and API/function descriptions | 05 |
| Analysis diagram generation and applied-transformation presentation | 05 |
| Model loading/checking, format import/export and explicit model/scaffold generation | 06; explicit model commands |
| 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 |
|---|---|
| Public project plugin entry point and DSL, stage composition, effective configuration/artifact resolution, and configuration of standalone lifecycle commands |
| Existing settings plugin ID, invocation/configuration-access coordination and loading the narrow LLVM task adapters; no transformation implementation or project-stage dependency |
| Shared Gradle adapter: declared inputs/outputs, |
| Gradle-independent request/change protocol, event records/reporting and atomic file/lease support |
| Metamodels, domain types and model rules; no stage, rendering or Gradle dependencies |
| Minimal shared process/file utilities, diagnostics and artifact contracts; no stage/engine dependencies and no blanket |
| Native C++ analyzer and Kotlin build/package/install orchestration, independent of JVM stage/report implementation |
| Authored documentation, examples, glossary and workplans |
| IDE integration and inspections using explicit model/contracts dependencies |
| Skills, references and distribution packaging |
| 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 |
|---|---|
| Stable Gradle engine adapter and task-observation actions; frontend logging and evidence-attribution services implement its observer interface |
| Typed raw-compiler and module/link tasks, their declared inputs/outputs and request serialization; loaded through the settings plugin |
| Existing typed P5 transformation task, declared inputs/outputs and request serialization |
| Compile-command/snapshot contracts, toolchain policy and common native process support; no model or rewrite implementation |
| Raw compiler execution, dependency validation and per-unit reuse |
| Copy raw outputs into owned preparation outputs, link and validate original LLVM; no rewrite-rule implementation |
| Shared pre/post-link rewrite algorithms and compiler-transform policy |
| Pre-link rewriting, optimization and analysis-input linking; uses the shared linker and rewrite engines |
| Final P5 transformations, validation and diagnostic evidence; does not depend on the preparation engine |
| 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.
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
NativeCompilationInputSnapshotFunctionalTestalready checks private source/header edits leave the other activity up to date;StigIncrementalCompilationFunctionalTestchecks per-unit reuse and invalidation.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.
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.
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.
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 |
|---|---|---|
|
| Reuse task outputs across builds — keep it. |
|
| Cache the task graph/config — keep it. |
|
| Reject new configuration-cache violations in checked builds. |
|
| Enables efficient input watching and |
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(orrm -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 —P6restores 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> --rerunfor a focused timing or regeneration check. Re-runningP6costs 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../stigbuild 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-DATEtask with missing required output indicates a declaration or producer bug to fix. Prefer a task-local--rerunwhen 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.