Path filters reference
Reference for the path-filter patterns that decide which Stella Ops CI workflows run for a given set of changed files. It is for CI authors who maintain .gitea/config/path-filters.yml and the workflows that consume it. Read the reality check below before relying on any per-module workflow name — much of the catalog is aspirational, and the active PR lane keys on change detection rather than these patterns.
Overview
Path filters determine which workflows run based on changed files. This ensures:
- Efficiency: only relevant tests run for each change.
- Speed: module-specific changes don’t trigger full builds.
- Cascading: shared-library changes trigger dependent module tests.
Configuration Location
Centralized path filter definitions are documented in:
.gitea/config/path-filters.yml
This file is the catalog of intended path filter patterns. Its own header states that each workflow should reference these patterns for consistency — it is a reference document, not a mechanism that workflows import at runtime.
Reality check (verified against
.gitea/on 2025-12-28 config / current workflows). The active .NET PR test lane does not use per-module workflow files keyed on these patterns. Instead,.gitea/workflows/dotnet-pr-tests.ymlruns adetectjob that calls.gitea/scripts/test/detect-affected-modules.sh, which diffs the PR against its base ref, maps changed files to top-levelsrc/<Module>directories that contain*.Tests.csproj, and setsaffects_all=truefor shared/global surface (src/__Libraries/**,src/__Analyzers/**,src/__Tests/**,Directory.*.props,global.json,nuget.config, and the test scripts themselves). Broad coverage is the job of the nightly.NET Test Sweep(dotnet-nightly-sweep.yml). The per-module<module>-*.ymlworkflow names referenced throughout this file and inpath-filters.ymlare largely aspirational — of the names below, onlyairgap-*.ymlresolves to an active workflow (airgap-federation-e2e.yml). Treat the per-module/categoriessections as a roadmap, not the running CI.
Path Filter Categories
1. Infrastructure Files (Trigger FULL CI)
Changes to these files trigger all tests and full build validation:
infrastructure:
- 'Directory.Build.props' # Root MSBuild properties
- 'Directory.Build.rsp' # MSBuild response file
- 'Directory.Packages.props' # Central package versions
- 'src/Directory.Build.props' # Source directory properties
- 'src/Directory.Packages.props'
- 'nuget.config' # NuGet feed configuration
- 'StellaOps.sln' # Aggregate solution (see note)
NOTE —
StellaOps.slndoes not resolve to a file.path-filters.ymllistsStellaOps.sln, but there is no root (orsrc/) aggregate solution in the repo; only per-module solutions exist (src/<Module>/StellaOps.<Module>.sln, 30 of them). The change-detection script (detect-affected-modules.sh) does still matchsrc/StellaOps.slnas a broad-change trigger defensively, but no such file is present today. CI build scripts deliberately avoid a monolithicdotnet build src/StellaOps.sln(it OOM-crashed the ~12 GB Gitea host on 2026-05-14) and build one project at a time instead.The doc previously also listed
src/**/StellaOps.*.slnand.gitea/workflows/**here; neither is inpath-filters.yml’sinfrastructureblock. Workflow changes are tracked under thedevops.workflowskey (.gitea/workflows/**), shown in the DevOps section below.
When to use: All PR-gating and integration workflows should include these paths.
2. Documentation Paths (Skip CI)
These paths should use paths-ignore to skip builds:
docs_ignore:
- 'docs/**' # All documentation
- '*.md' # Root markdown files
- '!CLAUDE.md' # Exception: Agent instructions SHOULD trigger
- '!AGENTS.md' # Exception: Module guidance SHOULD trigger
- 'etc/**' # Configuration samples
- 'LICENSE' # License file
- '.gitignore' # Git ignore
- '.editorconfig' # Editor configuration
Exceptions: These markdown files SHOULD trigger CI (encoded as negated patterns above, matching path-filters.yml):
CLAUDE.md- Agent instructions (affects behavior)AGENTS.md- Module-specific guidance
3. Shared Library Paths (Trigger Cascading)
Changes to shared libraries trigger tests in dependent modules:
Cryptography (CRITICAL - affects security)
cryptography:
paths:
- 'src/__Libraries/StellaOps.Cryptography*/**'
- 'src/Cryptography/**'
cascades_to:
- Scanner tests
- Attestor tests
- Authority tests
- EvidenceLocker tests
- Signer tests
- AirGap tests
- Security test suite
- Offline E2E tests
Evidence & Provenance
evidence:
paths:
- 'src/__Libraries/StellaOps.Evidence*/**'
- 'src/__Libraries/StellaOps.Provenance/**'
cascades_to:
- Scanner tests
- Attestor tests
- EvidenceLocker tests
- ExportCenter tests
- SbomService tests
Infrastructure & Database
infrastructure:
paths:
- 'src/__Libraries/StellaOps.Infrastructure*/**'
- 'src/__Libraries/StellaOps.DependencyInjection/**'
cascades_to:
- ALL integration tests
Replay & Determinism
replay:
paths:
- 'src/__Libraries/StellaOps.Replay*/**'
- 'src/__Libraries/StellaOps.Testing.Determinism/**'
cascades_to:
- Scanner determinism tests
- Determinism gate
- Replay module tests
Verdict & Policy Primitives
verdict:
paths:
- 'src/__Libraries/StellaOps.Verdict/**'
- 'src/__Libraries/StellaOps.DeltaVerdict/**'
cascades_to:
- Policy engine tests
- RiskEngine tests
- ReachGraph tests
Plugin Framework
plugin:
paths:
- 'src/__Libraries/StellaOps.Plugin/**'
cascades_to:
- Authority tests (plugin-based auth)
- Scanner tests (analyzer plugins)
- Concelier tests (connector plugins)
Configuration
configuration:
paths:
- 'src/__Libraries/StellaOps.Configuration/**'
cascades_to:
- ALL modules
src/__Libraries/StellaOps.Configuration/ is wired into nearly every service, so path-filters.yml cascades it to all_modules. (Note: the change-detection script in the active PR lane treats any src/__Libraries/** edit — Configuration included — as affects_all=true and defers to the nightly sweep rather than fanning out a job per module.)
Module-Specific Paths
Each module entry in path-filters.yml has source, tests, optional workflows, and optional dependencies keys. The Workflows column below reproduces the workflows: glob from the config — but, as noted at the top of this page, almost none of those workflow files exist yet (only airgap-*.yml does). Treat that column as the intended naming convention, not a list of live workflows. The active PR lane (dotnet-pr-tests.yml) keys solely on the top-level src/<Module>/** directory via change detection.
Core Platform
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| Authority | src/Authority/** | src/Authority/__Tests/** | authority-*.yml |
| Router (includes Gateway) | src/Router/** | src/Router/__Tests/** | router-*.yml |
| IssuerDirectory | src/Authority/StellaOps.IssuerDirectory/**, src/Authority/__Libraries/StellaOps.IssuerDirectory.*/** | src/Authority/__Tests/StellaOps.IssuerDirectory.Persistence.Tests/**, src/Authority/StellaOps.IssuerDirectory/StellaOps.IssuerDirectory.Core.Tests/** | — |
Scanning & Analysis
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| Scanner | src/Scanner/**, src/BinaryIndex/** | src/Scanner/__Tests/**, src/BinaryIndex/__Tests/** | scanner-*.yml, scanner-analyzers*.yml |
| BinaryIndex (Symbols merged in, Sprint 202) | src/BinaryIndex/** | src/BinaryIndex/__Tests/** | — |
AdvisoryAI (advisory_ai in config) | src/AdvisoryAI/** | src/AdvisoryAI/__Tests/** | advisory-*.yml |
| ReachGraph | src/ReachGraph/** | src/ReachGraph/__Tests/** | reachability-*.yml |
| Graph | src/Graph/** | src/Graph/__Tests/** | graph-*.yml |
Data Ingestion
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| Concelier (Feedser + Excititor absorbed, Sprint 203) | src/Concelier/** | src/Concelier/__Tests/** | concelier-*.yml, connector-*.yml |
| VexLens | src/VexLens/** | src/VexLens/__Tests/** | — |
| VexHub | src/VexHub/** | src/VexHub/__Tests/** | — |
| Mirror | src/Mirror/** | src/Mirror/__Tests/** | mirror-*.yml |
Artifacts & Evidence
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| Attestor (includes Signer, Provenance) | src/Attestor/** | src/Attestor/__Tests/** | attestation-*.yml, attestor-*.yml |
| Signer (sub-module) | src/Attestor/StellaOps.Signer/**, src/Attestor/__Libraries/StellaOps.Signer.*/** | src/Attestor/StellaOps.Signer/StellaOps.Signer.Tests/** | — |
| Provenance (sub-module) | src/Attestor/StellaOps.Provenance.*/** | src/Attestor/__Tests/StellaOps.Provenance.*/** | provenance-*.yml |
| SbomService | src/SbomService/** | src/SbomService/__Tests/** | — |
| EvidenceLocker | src/EvidenceLocker/** | src/EvidenceLocker/__Tests/** | evidence-*.yml |
| ExportCenter | src/ExportCenter/** | src/ExportCenter/__Tests/** | export-*.yml |
| Findings (includes RiskEngine, VulnExplorer) | src/Findings/** | src/Findings/__Tests/** | findings-*.yml, ledger-*.yml |
| RiskEngine (sub-module) | src/Findings/StellaOps.RiskEngine.*/** | src/Findings/__Tests/StellaOps.RiskEngine.*/** | — |
Policy & Risk
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| Policy | src/Policy/** | src/Policy/__Tests/** | policy-*.yml |
| Unknowns | src/Unknowns/** | src/Unknowns/__Tests/** | — |
NOTE —
Unknownsis not inpath-filters.yml.src/Unknowns/exists in the tree, but the configmodules:block has nounknownsentry. It is covered only generically by the change-detection script (anysrc/Unknowns/**change with a*.Tests.csprojpresent selects it).
Operations
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| JobEngine (includes Scheduler, TaskRunner, PacksRegistry — Sprint 208) | src/JobEngine/** | src/JobEngine/** (see note) | — |
| Scheduler (sub-module) | src/JobEngine/StellaOps.Scheduler.*/** | src/JobEngine/StellaOps.Scheduler.__Tests/** | — |
| TaskRunner (sub-module) | src/JobEngine/StellaOps.TaskRunner*/** | src/JobEngine/StellaOps.TaskRunner.__Tests/** | — |
| PacksRegistry (sub-module) | src/JobEngine/StellaOps.PacksRegistry*/** | src/JobEngine/StellaOps.PacksRegistry.__Tests/** (config still points at stale src/Orchestrator/...) | packs-*.yml |
| Notify (config folds Notifier in) | src/Notify/**, src/Notifier/** | src/Notify/__Tests/** | notify-*.yml |
| Timeline (includes TimelineIndexer) | src/Timeline/** | src/Timeline/__Tests/** | — |
| Replay | src/Replay/** | src/Replay/__Tests/** | replay-*.yml |
NOTE — JobEngine test path. Neither this doc’s earlier
src/JobEngine/__Tests/**norpath-filters.yml’ssrc/JobEngine/StellaOps.JobEngine/StellaOps.JobEngine.Tests/**resolves to a real directory. JobEngine test projects actually live under per-domain__Testsroots —src/JobEngine/StellaOps.Scheduler.__Tests/**,src/JobEngine/StellaOps.PacksRegistry.__Tests/**, andsrc/JobEngine/StellaOps.PacksRegistry/StellaOps.PacksRegistry.Tests/**. The resilient pattern is the top-levelsrc/JobEngine/**, which is what change detection uses. (Config also listsNotifieras part ofnotify; there is a separatesrc/Notifier/tree but no standalonenotifierconfig entry, andpath-filters.ymldoes not listTimelineat all.)
Infrastructure
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| Cryptography | src/Cryptography/** | src/__Libraries/__Tests/StellaOps.Cryptography*/** | crypto-*.yml |
| Telemetry | src/Telemetry/** | src/Telemetry/__Tests/** | — |
| Signals | src/Signals/** | src/Signals/__Tests/** | signals-*.yml |
| AirGap | src/AirGap/** | src/AirGap/__Tests/** | airgap-*.yml, offline-*.yml (only airgap-federation-e2e.yml exists) |
| AOC | src/Aoc/** | src/Aoc/__Tests/** | aoc-*.yml |
Integration
| Module | Source Paths | Test Paths | Workflows (aspirational) |
|---|---|---|---|
| Integrations | src/Integrations/** | src/Integrations/__Tests/** | — |
| CLI | src/Cli/** | src/Cli/__Tests/** | cli-*.yml |
| Web | src/Web/** | src/Web/**/*.spec.ts | lighthouse-*.yml |
NOTE —
Integrations.__Extensions.path-filters.ymlflags thatsrc/Integrations/__Extensions/holds non-.NET IDE plugins (TypeScript/Kotlin) that do not participate in .NET CI; separate npm/gradle CI would be required. Active FE workflows (fe-web-tests.yml,fe-e2e-tests.yml) gatesrc/Web/StellaOps.Web/**specs — thesrc/Web/**/*.spec.tsglob above is the config’s broader convention.
DevOps & CI/CD Paths
These mirror the devops: block in path-filters.yml. The config keeps each entry to a single broad glob; the doc previously listed extra sub-globs that are either redundant or do not match anything — corrected/annotated below.
Docker & Containers
docker:
- 'devops/docker/**'
- '**/Dockerfile'
**/Dockerfiledoes NOT matchDockerfile.<flavour>files (e.g.devops/docker/Dockerfile.console,Dockerfile.ci), and many such files exist. If you want those covered, add'**/Dockerfile.*'—path-filters.ymlcurrently omits it.
Compose Profiles
compose:
- 'devops/compose/**'
The doc previously also listed
docker-compose*.yml; there are no compose files at the repo root. They all live underdevops/compose/, already covered by the glob above.
Helm Charts
helm:
- 'devops/helm/**'
The doc previously also listed
devops/helm/stellaops/**; no such subchart exists —devops/helm/currently contains only aREADME.md. The broad glob is the onlyhelmentry inpath-filters.yml.
Database
database:
- 'devops/database/**'
devops/database/postgres/exists but is already covered bydevops/database/**;path-filters.ymldoes not list it separately.
CI/CD Scripts
scripts:
- '.gitea/scripts/**'
path-filters.yml’sdevops.scriptslists only.gitea/scripts/**. The doc previously addeddevops/scripts/**(that directory does exist, but it is not in the config entry).
Workflows
workflows:
- '.gitea/workflows/**'
Workflow-file changes are tracked under
devops.workflows, not the infrastructure block. This is the canonical home for the.gitea/workflows/**pattern.
Test Infrastructure Paths
These mirror the test_infrastructure: block in path-filters.yml. The config keeps each entry to one broad glob; the sub-globs the doc previously listed are real directories but redundant under the parent glob — except StellaOps.TestKit, which does not exist.
Global Test Suites
global_tests:
- 'src/__Tests/**'
Sub-suites like
src/__Tests/Integration/**,.../architecture/**,.../security/**,.../chaos/**, and.../e2e/**all exist on disk but are already covered bysrc/__Tests/**. Note: any change undersrc/__Tests/**is classified asaffects_all=trueby the change-detection script, deferring to the nightly sweep.
Shared Test Libraries
shared_libraries:
- 'src/__Tests/__Libraries/**'
path-filters.ymllists only the parent glob (key nameshared_libraries, nottest_libraries).src/__Tests/__Libraries/StellaOps.Infrastructure.Postgres.Testing/exists and is covered by it, butStellaOps.TestKitdoes not exist atsrc/__Tests/__Libraries/— drop that pattern.
Test Datasets & Benchmarks
datasets:
- 'src/__Tests/__Datasets/**'
benchmarks:
- 'src/__Tests/__Benchmarks/**'
In
path-filters.ymlthese are two separate keys (datasetsandbenchmarks); the doc previously merged__Benchmarksintodatasets.
Example Workflow Configurations
PR-Gating Workflow (Skip Docs)
on:
push:
branches: [main]
paths-ignore:
- 'docs/**'
- '*.md'
- 'etc/**'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- 'etc/**'
Module-Specific Workflow (With Cascading) — illustrative convention
This block illustrates the intended convention; no
scanner-*.ymlworkflow exists today. The active scanner test coverage comes from the change-detection PR lane (dotnet-pr-tests.yml) and the nightly sweep, not a dedicated per-module workflow. Cascade/dependency globs below match thescannerentry’sdependenciesinpath-filters.yml.
on:
push:
branches: [main]
paths:
# Direct module paths
- 'src/Scanner/**'
- 'src/BinaryIndex/**'
# Shared library cascades (path-filters.yml: modules.scanner.dependencies)
- 'src/__Libraries/StellaOps.Evidence*/**'
- 'src/__Libraries/StellaOps.Cryptography*/**'
- 'src/__Libraries/StellaOps.Replay*/**'
- 'src/__Libraries/StellaOps.Provenance/**'
# Infrastructure cascades
- 'Directory.Build.props'
- 'Directory.Packages.props'
# Self-reference (would be created alongside the workflow file)
- '.gitea/workflows/scanner-*.yml'
pull_request:
paths:
- 'src/Scanner/**'
- 'src/BinaryIndex/**'
- 'src/__Libraries/StellaOps.Evidence*/**'
- 'src/__Libraries/StellaOps.Cryptography*/**'
Real example — workflow-renderer.yml (live workflow)
This active workflow is a concrete instance of the path-filter + self-reference convention above:
on:
pull_request:
paths:
- 'src/Workflow/__Libraries/StellaOps.Workflow.Renderer.ElkSharp/**'
- 'src/Workflow/__Libraries/StellaOps.Workflow.Renderer.ElkJs/**'
- 'src/Workflow/__Libraries/StellaOps.Workflow.Renderer.Svg/**'
- 'src/Workflow/__Libraries/StellaOps.Workflow.Renderer.Msagl/**'
- 'src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/**'
- 'src/__Libraries/StellaOps.ElkSharp/**'
- 'tools/elk-stress/**'
- '.gitea/workflows/workflow-renderer.yml' # self-reference
workflow_dispatch: {}
schedule:
- cron: '0 6 * * *'
Documentation-Only Workflow
on:
push:
paths:
- 'docs/**'
- '*.md'
pull_request:
paths:
- 'docs/**'
- '*.md'
The doc previously listed
scripts/render_docs.pyas an extra trigger; no such script exists in the repo. (The only render script underscripts/is.gitea/scripts/test/render-test-dashboard.py, which renders the test dashboard, not docs.) There is also no active docs-only CI workflow at present.
Docker/Container Workflow
on:
push:
paths:
- '**/Dockerfile'
- '**/Dockerfile.*' # needed to catch Dockerfile.<flavour> files
- 'devops/docker/**'
schedule:
- cron: '0 4 * * *' # Also run daily for vulnerability updates
Note the
**/Dockerfile.*line: it is required to catch the manyDockerfile.<flavour>files indevops/docker/but is absent frompath-filters.yml’sdevops.dockerentry (which lists only**/Dockerfile).
Validation Checklist
When adding or modifying path filters:
- [ ] Does the workflow skip docs-only changes? (Use
paths-ignore) - [ ] Does the workflow include dependent shared library paths? (Cascading)
- [ ] Does the workflow include infrastructure files for full builds?
- [ ] Are glob patterns correct? (
**for recursive,*for single level) - [ ] Is the workflow self-referenced? (e.g.,
.gitea/workflows/module-*.yml)
Glob Pattern Reference
| Pattern | Matches |
|---|---|
src/** | All files under src/ recursively |
src/* | Direct children of src/ only |
**/*.cs | All .cs files anywhere |
*.md | Markdown files in root only |
src/**/*.csproj | All .csproj files under src/ |
!src/**/*.md | Exclude markdown in src/ |
**/Dockerfile* | Dockerfile, Dockerfile.prod, etc. |
Related Documentation
- Workflow Triggers - Complete trigger reference
- Test Strategy - Test categories and execution
- CI/CD Overview - Architecture overview
