Skip to content

feat/v2-situation-config: Introduce Situation/Action/Mode model for v2 decision tree#19

Merged
vedanthvdev merged 1 commit intomasterfrom
feat/v2-situation-config
Apr 22, 2026
Merged

feat/v2-situation-config: Introduce Situation/Action/Mode model for v2 decision tree#19
vedanthvdev merged 1 commit intomasterfrom
feat/v2-situation-config

Conversation

@vedanthvdev
Copy link
Copy Markdown
Owner

@vedanthvdev vedanthvdev commented Apr 22, 2026

Summary

Phase 1 of the v2 design in docs/DESIGN-v2.md. Replaces the two legacy boolean flags with a richer per-Situation decision model so users can independently configure SELECTED, FULL_SUITE or SKIPPED on each distinct branch the engine can take. The legacy flags are still honoured through a shim so zero-config users keep today's safety net.

What changes

  • New enums Action (SELECTED / FULL_SUITE / SKIPPED), Situation (EMPTY_DIFF, ALL_FILES_IGNORED, ALL_FILES_OUT_OF_SCOPE, UNMAPPED_FILE, DISCOVERY_EMPTY, DISCOVERY_SUCCESS) and Mode (AUTO / LOCAL / CI / STRICT) drive a rewritten AffectedTestsEngine that follows one top-to-bottom decision tree.
  • New path categories ignorePaths (files that must not influence selection, e.g. *.md, LICENSE, generated code) and outOfScopeTestDirs / outOfScopeSourceDirs (e.g. api-test/src/test/java, built by a different Gradle task). PathToClassMapper now buckets a diff into ignored / out-of-scope / production / test / unmapped, and ProjectIndex filters the same dirs so discovery never picks up out-of-scope tests.
  • Strict resolution precedence in AffectedTestsConfig: explicit v2 settings > legacy boolean translation > Mode defaults > pre-v2 hardcoded defaults.
  • Raised defaults transitiveDepth=4, implementationNaming now includes Default, richer ignorePaths covering root-level *.md/*.txt/LICENSE/CHANGELOG/images at both the repo root and nested paths.
  • Gradle surface AffectedTestsExtension exposes mode, ignorePaths, outOfScopeTestDirs, outOfScopeSourceDirs and per-situation overrides (onEmptyDiff, onAllFilesIgnored, onAllFilesOutOfScope, onUnmappedFile, onDiscoveryEmpty). The escalation log line names both the v2 decision and the legacy flag name for grep compatibility.
  • Backwards compatibility excludePaths aliases ignorePaths; runAllIfNoMatches and runAllOnNonJavaChange continue to work and translate into UNMAPPED_FILE / DISCOVERY_EMPTY actions.
  • Docs rewritten alongside the codeREADME.md now leads with the v2 Situation/Action/Mode model, documents the resolution-priority ladder, and maps every legacy flag to the v2 situation it translates to. docs/architecture.svg is regenerated to show the five decision branches and the four-tier action-resolution ladder.

Why

The api-test-only regression that used to trigger a full unit-test run now routes to ALL_FILES_OUT_OF_SCOPE → SKIPPED, and a docs-only diff now routes to ALL_FILES_IGNORED → SKIPPED on zero-config installs — the two scenarios that drove the v2 design.

Test plan

  • ./gradlew check (87 tests pass)
  • New engine-level regressions for api-test-only, markdown-only, and Mode.CI DISCOVERY_EMPTY
  • PathToClassMapperTest covers ignored / out-of-scope / unmapped buckets
  • AffectedTestsConfigTest covers explicit-situation precedence, legacy boolean shim, mode defaults and ignorePaths aliasing excludePaths
  • AffectedTestTaskLogFormatTest covers v2 phrasing + legacy grep compatibility
  • README and docs/architecture.svg rewritten to match the shipped v2 API
  • Follow-up PRs: --explain task flag and richer summary log format — tracked for Phase 1 close-out

Related

…2 decision tree

This commit realises Phase 1 of the v2 design (docs/DESIGN-v2.md) by replacing
the two legacy boolean flags (`runAllIfNoMatches`, `runAllOnNonJavaChange`)
with a richer per-situation decision model so every user who adopts the
plugin can express "selected / full suite / skipped" on each distinct
branch the engine can take, without giving up the existing safety net.

Three new enums — `Action` (SELECTED, FULL_SUITE, SKIPPED), `Situation`
(EMPTY_DIFF, ALL_FILES_IGNORED, ALL_FILES_OUT_OF_SCOPE, UNMAPPED_FILE,
DISCOVERY_EMPTY, DISCOVERY_SUCCESS) and `Mode` (AUTO, LOCAL, CI, STRICT)
— now drive `AffectedTestsEngine`, which has been rewritten to follow a
single top-to-bottom decision tree: ignore the diff → bucket files into
ignored / out-of-scope / production / test / unmapped → resolve the
matching `Situation` → look up the configured `Action` and either
short-circuit (FULL_SUITE or SKIPPED) or continue into discovery. This
makes the common cases visible from the log line itself and removes the
hidden coupling between the two legacy flags.

`PathToClassMapper` and `ProjectIndex` gained first-class support for
two new path categories — `ignorePaths` (files that must not influence
test selection, e.g. markdown/generated) and `outOfScopeTestDirs` /
`outOfScopeSourceDirs` (source sets like `api-test` that are built by a
separate Gradle task and must not be dispatched here). The api-test-only
regression that used to trigger a full unit-test run now routes to
`ALL_FILES_OUT_OF_SCOPE → SKIPPED`, and a docs-only diff now routes to
`ALL_FILES_IGNORED → SKIPPED` on zero-config installs because the default
ignore list covers `*.md`, `*.txt`, LICENSE, CHANGELOG and common image
formats at both the repository root and nested paths.

`AffectedTestsConfig` resolves each `Situation → Action` with a strict
precedence so nobody silently regresses: explicit v2 settings win; then
the two legacy booleans translate into `UNMAPPED_FILE` and
`DISCOVERY_EMPTY` actions for users who haven't migrated yet; then the
`Mode` profile (CI biases toward FULL_SUITE, LOCAL toward SKIPPED,
STRICT is paranoid, AUTO sniffs the `CI` env var) supplies defaults;
and finally the pre-v2 hardcoded defaults (`runAllIfNoMatches=true`,
`runAllOnNonJavaChange=true`) apply so zero-config users keep their
current safety net. Default `transitiveDepth` is raised to 4 to match
typical controller→service→repo chains, `implementationNaming` now
includes the `Default` prefix idiomatic in Spring code, and the legacy
`excludePaths` getter is preserved but aliases `ignorePaths`.

The Gradle extension exposes `mode`, `ignorePaths`,
`outOfScopeTestDirs`, `outOfScopeSourceDirs` and per-situation overrides
(`onEmptyDiff`, `onAllFilesIgnored`, `onAllFilesOutOfScope`,
`onUnmappedFile`, `onDiscoveryEmpty`), and the task's escalation log now
names both the v2 decision and the legacy flag name for grep
compatibility. Tests cover the new routing, the legacy shim, mode
defaults, default ignore-path glob coverage at the repo root and the
api-test-only scenario end-to-end; the full plugin `./gradlew check`
passes with 87 tests.

The README and architecture diagram are rewritten alongside the code so
new users start with the v2 API (mode, per-situation actions, path
buckets, the resolution-priority ladder) and existing users see their
legacy flags mapped explicitly to the v2 situations they translate to.
The rendered diagram in `docs/architecture.svg` now shows the five
decision branches and the four-tier action-resolution ladder.
@vedanthvdev vedanthvdev force-pushed the feat/v2-situation-config branch from a6268a8 to 5316b52 Compare April 22, 2026 09:01
@vedanthvdev vedanthvdev merged commit fd2a3e1 into master Apr 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant