pytest-selective 0.1.1__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/dependabot.yml +4 -0
  2. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/test-lanes.json +5 -1
  3. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/workflows/ci.yml +3 -3
  4. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/workflows/observe-ci.yml +1 -1
  5. pytest_selective-0.2.0/.github/workflows/pr-title.yml +45 -0
  6. pytest_selective-0.2.0/.github/workflows/public-actions.yml +54 -0
  7. pytest_selective-0.2.0/.github/workflows/release-please.yml +54 -0
  8. pytest_selective-0.2.0/.release-please-manifest.json +3 -0
  9. pytest_selective-0.2.0/AGENTS.md +58 -0
  10. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/CHANGELOG.md +12 -0
  11. pytest_selective-0.2.0/CLAUDE.md +1 -0
  12. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/CONTRIBUTING.md +62 -0
  13. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/PKG-INFO +33 -19
  14. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/README.md +32 -18
  15. pytest_selective-0.2.0/RELEASING.md +114 -0
  16. pytest_selective-0.2.0/action.yml +106 -0
  17. pytest_selective-0.2.0/agentsync.toml +18 -0
  18. pytest_selective-0.2.0/docs/actions.md +42 -0
  19. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/agents.md +6 -12
  20. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/ci-toolkit.md +16 -0
  21. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/ci.md +25 -5
  22. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/comparison-pytest-impacted.md +82 -5
  23. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/pytest-hygiene.md +2 -2
  24. pytest_selective-0.2.0/docs/selection-health.md +47 -0
  25. pytest_selective-0.2.0/docs/work-in-progress/tickets/codex-selector-correctness-performance-test-plan.md +16 -0
  26. pytest_selective-0.2.0/docs/work-in-progress/tickets/public-action-onboarding-test-plan.md +7 -0
  27. pytest_selective-0.2.0/plan-lanes/action.yml +33 -0
  28. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/pyproject.toml +1 -1
  29. pytest_selective-0.2.0/pytest-expansion/action.yml +35 -0
  30. pytest_selective-0.2.0/release-please-config.json +76 -0
  31. pytest_selective-0.2.0/scripts/benchmark_graph.py +67 -0
  32. pytest_selective-0.2.0/scripts/benchmark_rust.py +68 -0
  33. pytest_selective-0.2.0/scripts/public_actions.py +55 -0
  34. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/scripts/smoke_distribution.py +4 -1
  35. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/skills/pytest-selective/SKILL.md +21 -0
  36. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/skills/pytest-selective/references/adoption.md +16 -2
  37. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_graph.py +100 -60
  38. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_models.py +8 -0
  39. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_selection.py +6 -0
  40. pytest_selective-0.2.0/src/pytest_selective/parse_batch.py +72 -0
  41. pytest_selective-0.2.0/src/pytest_selective/pytest_plugins.py +108 -0
  42. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/pytest_sharding.py +10 -0
  43. pytest_selective-0.2.0/test-impact/action.yml +106 -0
  44. pytest_selective-0.2.0/tests/test_public_actions.py +30 -0
  45. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/test_repository_ci.py +2 -0
  46. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_impact_graph.py +27 -0
  47. pytest_selective-0.2.0/tests/testing/test_parse_batch.py +43 -0
  48. pytest_selective-0.2.0/tests/testing/test_pytest_plugins.py +168 -0
  49. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/uv.lock +1 -1
  50. pytest_selective-0.1.1/AGENTS.md +0 -23
  51. pytest_selective-0.1.1/RELEASING.md +0 -63
  52. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.gitattributes +0 -0
  53. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  54. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  55. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/actions/plan-lanes/action.yml +0 -0
  56. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/actions/pytest-expansion/action.yml +0 -0
  57. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/actions/test-impact/action.yml +0 -0
  58. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/workflows/release.yml +0 -0
  59. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.github/workflows/windows-performance.yml +0 -0
  60. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.gitignore +0 -0
  61. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/.pre-commit-config.yaml +0 -0
  62. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/LICENSE +0 -0
  63. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/PROVENANCE.md +0 -0
  64. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/README.md +0 -0
  65. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-due-ci.json +0 -0
  66. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-due-docs-ci.json +0 -0
  67. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-due-docs-widget.json +0 -0
  68. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-due-widget.json +0 -0
  69. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-input-replays.json +0 -0
  70. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-obligation-docs.json +0 -0
  71. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-obligation.json +0 -0
  72. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-routing.md +0 -0
  73. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22-selective-docs.json +0 -0
  74. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-22.md +0 -0
  75. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/obligation-baseline.json +0 -0
  76. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after-3.11.xml +0 -0
  77. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after-3.14.xml +0 -0
  78. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after.json +0 -0
  79. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control-3.11.xml +0 -0
  80. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control-3.14.xml +0 -0
  81. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control.json +0 -0
  82. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-earlier.json +0 -0
  83. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/2026-10-23-windows-saleor.md +0 -0
  84. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/benchmarks/windows-runtime.md +0 -0
  85. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/configuration.md +0 -0
  86. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/evidence.md +0 -0
  87. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/local-development.md +0 -0
  88. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/pytest-impacted.md +0 -0
  89. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/tutorial.md +0 -0
  90. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/work-in-progress/tickets/codex-windows-git-performance-test-plan.md +0 -0
  91. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/docs/work-in-progress/tickets/impacted-improvements-test-plan.md +0 -0
  92. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/scripts/benchmark_parsing.py +0 -0
  93. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/scripts/check_docs.py +0 -0
  94. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/scripts/check_metadata.py +0 -0
  95. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/scripts/compare_impacted.py +0 -0
  96. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/scripts/measure_ci_runs.py +0 -0
  97. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/scripts/tutorial.py +0 -0
  98. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/skills/pytest-selective/agents/openai.yaml +0 -0
  99. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/__init__.py +0 -0
  100. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/__main__.py +0 -0
  101. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/ast_imports.py +0 -0
  102. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/ci.py +0 -0
  103. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/hygiene.py +0 -0
  104. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_audit.py +0 -0
  105. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_audit_plugin.py +0 -0
  106. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_cli.py +0 -0
  107. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_declarations.py +0 -0
  108. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_explanation.py +0 -0
  109. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_first_party.py +0 -0
  110. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/impact_name_scope.py +0 -0
  111. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/input_policy.py +0 -0
  112. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/local.py +0 -0
  113. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/plugin.py +0 -0
  114. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/py.typed +0 -0
  115. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/pytest_expansion.py +0 -0
  116. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/test_inventory.py +0 -0
  117. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/typecheck_scope.py +0 -0
  118. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/src/pytest_selective/working_tree.py +0 -0
  119. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/__init__.py +0 -0
  120. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/test_ci_measurements.py +0 -0
  121. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/test_distribution_metadata.py +0 -0
  122. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/test_hygiene.py +0 -0
  123. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/test_pytest_expansion.py +0 -0
  124. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/test_repository_hygiene.py +0 -0
  125. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/test_tutorial.py +0 -0
  126. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/__init__.py +0 -0
  127. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/git_repo.py +0 -0
  128. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_ast_imports.py +0 -0
  129. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_ci.py +0 -0
  130. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_git_repo.py +0 -0
  131. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_global_inputs.py +0 -0
  132. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_impact_audit.py +0 -0
  133. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_impact_explanation.py +0 -0
  134. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_impact_first_party.py +0 -0
  135. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_impact_name_scope.py +0 -0
  136. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_portability.py +0 -0
  137. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_pytest_plugin.py +0 -0
  138. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_pytest_sharding.py +0 -0
  139. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_typecheck_scope.py +0 -0
  140. {pytest_selective-0.1.1 → pytest_selective-0.2.0}/tests/testing/test_working_tree.py +0 -0
@@ -2,6 +2,8 @@ version: 2
2
2
  updates:
3
3
  - package-ecosystem: github-actions
4
4
  directory: /
5
+ commit-message:
6
+ prefix: ci
5
7
  schedule:
6
8
  interval: weekly
7
9
  groups:
@@ -9,6 +11,8 @@ updates:
9
11
  patterns: ["*"]
10
12
  - package-ecosystem: uv
11
13
  directory: /
14
+ commit-message:
15
+ prefix: build
12
16
  schedule:
13
17
  interval: weekly
14
18
  groups:
@@ -33,6 +33,10 @@
33
33
  ".github/test-lanes.json",
34
34
  ".github/workflows/ci.yml",
35
35
  ".github/workflows/release.yml",
36
- ".github/actions/**"
36
+ ".github/actions/**",
37
+ "action.yml",
38
+ "*/action.yml",
39
+ "examples/**",
40
+ ".github/workflows/public-actions.yml"
37
41
  ]
38
42
  }
@@ -3,7 +3,7 @@ on:
3
3
  push:
4
4
  branches: [main]
5
5
  pull_request:
6
- types: [opened, synchronize, reopened, labeled, unlabeled]
6
+ types: [opened, synchronize, reopened]
7
7
  workflow_dispatch:
8
8
  workflow_call:
9
9
  permissions:
@@ -22,11 +22,11 @@ jobs:
22
22
  with:
23
23
  fetch-depth: 0
24
24
  - id: plan
25
- uses: ./.github/actions/plan-lanes
25
+ uses: ./plan-lanes
26
26
  with:
27
27
  config: .github/test-lanes.json
28
28
  base: ${{ github.event.pull_request.base.sha || github.event.before }}
29
- full: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'test:full') }}
29
+ full: ${{ github.run_attempt > 1 || github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'test:full') }}
30
30
  quality:
31
31
  runs-on: ubuntu-latest
32
32
  steps:
@@ -13,7 +13,7 @@ permissions:
13
13
 
14
14
  jobs:
15
15
  report:
16
- uses: gigaverse-app/ci-esta/.github/workflows/report.yml@v0.1
16
+ uses: gigaverse-app/ci-esta/.github/workflows/report.yml@v0.3.0
17
17
  with:
18
18
  run-id: ${{ github.event.workflow_run.id }}
19
19
  run-attempt: ${{ github.event.workflow_run.run_attempt }}
@@ -0,0 +1,45 @@
1
+ name: PR title
2
+
3
+ # Squash merges use this checked title as the Conventional Commit header.
4
+ on:
5
+ pull_request_target:
6
+ types: [opened, edited, synchronize, reopened, ready_for_review]
7
+
8
+ permissions:
9
+ pull-requests: read
10
+
11
+ jobs:
12
+ conventional-commit:
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 5
15
+ steps:
16
+ # Only reads PR metadata. Never check out or execute PR code in this workflow.
17
+ - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
18
+ with:
19
+ types: |
20
+ feat
21
+ fix
22
+ perf
23
+ revert
24
+ docs
25
+ style
26
+ refactor
27
+ test
28
+ build
29
+ ci
30
+ chore
31
+ requireScope: false
32
+ env:
33
+ GITHUB_TOKEN: ${{ github.token }}
34
+ - name: Explain how to repair the title
35
+ if: failure()
36
+ run: |
37
+ cat >> "$GITHUB_STEP_SUMMARY" <<'EOF'
38
+ Rename the PR to `type(optional-scope): description`, for example
39
+ `fix(parser): handle empty input` or `docs: clarify installation`.
40
+ Use `!` before the colon for a breaking change, for example
41
+ `feat(api)!: remove the deprecated argument`.
42
+ Choose the type that describes the change; do not hide features or fixes under `chore:`.
43
+ Editing the PR title reruns this check. No commit rewrite or replacement PR is needed.
44
+ If the title is already valid, inspect the action log for an API or runner failure.
45
+ EOF
@@ -0,0 +1,54 @@
1
+ name: Public action smoke
2
+ on:
3
+ pull_request:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+ permissions:
8
+ contents: read
9
+ jobs:
10
+ public-actions:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
14
+ with:
15
+ fetch-depth: 0
16
+ - name: Use the reviewed repository graph
17
+ run: |
18
+ python - <<'PY'
19
+ import json
20
+ from pathlib import Path
21
+ graph = json.loads(Path('.github/test-lanes.json').read_text())['graph']
22
+ Path('smoke-impact.json').write_text(json.dumps(graph))
23
+ PY
24
+ - uses: ./
25
+ id: impact
26
+ with:
27
+ config: smoke-impact.json
28
+ base: ${{ github.sha }}
29
+ full: 'true'
30
+ full-roots: tests
31
+ max-shards: '2'
32
+ explanation-artifact: ''
33
+ - name: Verify forwarded file-plan outputs
34
+ env:
35
+ MODE: ${{ steps.impact.outputs.mode }}
36
+ ROOTS: ${{ steps.impact.outputs.test_roots }}
37
+ run: |
38
+ test "$MODE" = full
39
+ test -n "$ROOTS"
40
+ - uses: ./plan-lanes
41
+ id: lanes
42
+ with:
43
+ config: .github/test-lanes.json
44
+ base: ${{ github.sha }}
45
+ full: 'true'
46
+ artifact-name: ''
47
+ - name: Verify forwarded lane outputs
48
+ env:
49
+ LANES: ${{ steps.lanes.outputs.lanes }}
50
+ run: |
51
+ python - <<'PY'
52
+ import json, os
53
+ assert json.loads(os.environ['LANES']) == {'tests': True}
54
+ PY
@@ -0,0 +1,54 @@
1
+ name: Release Please
2
+
3
+ # Release PRs accumulate changes; merging one is the publishing decision.
4
+ on:
5
+ workflow_run:
6
+ workflows: [CI]
7
+ branches: [main]
8
+ types: [completed]
9
+
10
+ permissions: {}
11
+
12
+ concurrency:
13
+ group: release-please
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ release-please:
18
+ if: >-
19
+ github.event.workflow_run.event == 'push'
20
+ && github.event.workflow_run.conclusion == 'success'
21
+ && github.event.workflow_run.head_repository.full_name == github.repository
22
+ runs-on: ubuntu-latest
23
+ environment: release-automation
24
+ timeout-minutes: 10
25
+ permissions:
26
+ contents: write
27
+ pull-requests: write
28
+ steps:
29
+ - name: Only process the tested main head
30
+ id: current
31
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
32
+ with:
33
+ script: |
34
+ const {data: branch} = await github.rest.repos.getBranch({...context.repo, branch: 'main'});
35
+ core.setOutput('matches', branch.commit.sha === context.payload.workflow_run.head_sha);
36
+ - name: Require release bot authentication
37
+ if: steps.current.outputs.matches == 'true'
38
+ env:
39
+ HAS_RELEASE_TOKEN: ${{ secrets.GV_CI_CROSS_REPO_TOKEN != '' }}
40
+ run: |
41
+ if [[ "$HAS_RELEASE_TOKEN" != "true" ]]; then
42
+ echo "::error::Share the organization GV_CI_CROSS_REPO_TOKEN secret with this repository."
43
+ exit 1
44
+ fi
45
+ - name: Prepare release PR or publish its GitHub release
46
+ if: steps.current.outputs.matches == 'true'
47
+ uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
48
+ with:
49
+ # This credential triggers CI on release PRs and Publish on releases.
50
+ # GITHUB_TOKEN would suppress those follow-up workflow events.
51
+ token: ${{ secrets.GV_CI_CROSS_REPO_TOKEN }}
52
+ target-branch: main
53
+ config-file: release-please-config.json
54
+ manifest-file: .release-please-manifest.json
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.0"
3
+ }
@@ -0,0 +1,58 @@
1
+ # Working on pytest-selective
2
+
3
+ For adopting the tool in another repository, use
4
+ [the portable skill](skills/pytest-selective/SKILL.md). This file describes work
5
+ on pytest-selective itself.
6
+
7
+ - Read [CONTRIBUTING.md](CONTRIBUTING.md) for setup and validation. Use the locked
8
+ environment: `uv sync --locked`, `uv run pre-commit run --all-files`,
9
+ `uv run pytest -q -n 4`. For packaging changes also build, run strict Twine,
10
+ `scripts/check_metadata.py` and `scripts/smoke_distribution.py`.
11
+ - Reproduce selection bugs using real temporary Git repositories and existing
12
+ `tests/testing/git_repo.py` helpers. Cover base and head trees, deleted inputs,
13
+ explicit declarations and the relevant fallback. Do not mock away selection.
14
+ - Planning supports committed revisions and explicit working-tree snapshots. Preserve full execution on
15
+ operational uncertainty and diagnostics for invalid declarations. An empty
16
+ selection is not an empty pytest argument list.
17
+ - Keep consumer routing regressions in the always-running quality job. Update
18
+ `.github/test-lanes.json` when adding execution inputs; preserve full main/manual
19
+ checkpoints and the `test:full` override.
20
+ - The README's performance numbers are scenario-specific observations. Keep
21
+ claims linked to [raw evidence](docs/benchmarks/2026-10-22-routing.md); distinguish
22
+ runner-seconds, elapsed time and billing. Skill/example edits need usable links
23
+ and verified commands, not tests that merely assert prose wording.
24
+
25
+ ## Commits and pull requests
26
+
27
+ - Use Conventional Commits for commits you create and PR titles:
28
+ `type(optional-scope): description`, for example
29
+ `fix(parser): handle empty input`.
30
+ - Allowed types: `feat`, `fix`, `perf`, `revert`, `docs`, `style`,
31
+ `refactor`, `test`, `build`, `ci`, and `chore`. Choose the type for the
32
+ actual change. Mark breaking changes with `!` before the colon and explain
33
+ the migration in the PR body.
34
+ - Repair an invalid PR title in place. Preserve useful work; do not close or
35
+ replace the PR, or rewrite existing commits just to satisfy the title check.
36
+ - Squash merges use the checked PR title. Keep any `BREAKING CHANGE:` details
37
+ in the body. Follow [CONTRIBUTING.md](CONTRIBUTING.md) and
38
+ [RELEASING.md](RELEASING.md).
39
+
40
+ ## Releases
41
+
42
+ Release Please derives versions and changelogs from Conventional Commits. Let
43
+ it prepare the release PR; do not hand-edit versions for ordinary changes.
44
+ Merging a release PR authorizes PyPI publication after CI. Follow RELEASING.md.
45
+
46
+ ## Shared agent instructions
47
+
48
+ Edit this root `AGENTS.md` as the single source for Codex and Claude.
49
+ `CLAUDE.md` is an AgentSync-managed relative symlink to this file, not a
50
+ separate instruction document. The configuration is
51
+ [agentsync.toml](agentsync.toml). To restore and verify the link:
52
+
53
+ ```bash
54
+ npx --yes @dallay/agentsync@1.52.3 apply
55
+ npx --yes @dallay/agentsync@1.52.3 status
56
+ ```
57
+
58
+ Keep the symlink tracked in Git. See CONTRIBUTING.md for platform setup.
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0](https://github.com/gigaverse-app/pytest-selective/compare/v0.1.1...v0.2.0) (2026-10-23)
4
+
5
+
6
+ ### Features
7
+
8
+ * add public action entry points and task-focused onboarding ([#41](https://github.com/gigaverse-app/pytest-selective/issues/41)) ([94da1e6](https://github.com/gigaverse-app/pytest-selective/commit/94da1e6d4088d9ded93ce491dc88993ac140e0ea))
9
+
10
+
11
+ ### Bug fixes
12
+
13
+ * **selection:** preserve plugin sessions and accelerate graph construction ([#42](https://github.com/gigaverse-app/pytest-selective/issues/42)) ([2994c88](https://github.com/gigaverse-app/pytest-selective/commit/2994c887d916a965b78f5ff8d48476abed705e37))
14
+
3
15
  ## 0.1.1 (2026-10-23)
4
16
 
5
17
  - Register a native pytest plugin: `pytest --selective`, ini defaults, optional existing impact JSON, an exact comparison base, and `--no-selective` for full execution.
@@ -0,0 +1 @@
1
+ AGENTS.md
@@ -61,3 +61,65 @@ matrix. Main, manual/called runs and the `test:full` label run it in full; a
61
61
  failed planner also runs all tests. Repository routing controls exercise the
62
62
  committed config against real Git trees, including full and missing-history
63
63
  controls. Add new non-import execution inputs to `.github/test-lanes.json`.
64
+
65
+ ## Conventional Commits
66
+
67
+ Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
68
+ for commits you create and PR titles (the squash commit that lands on `main`):
69
+
70
+ ```text
71
+ fix(parser): handle empty input
72
+ feat: add a new output format
73
+ feat(api)!: remove the deprecated argument
74
+ docs: clarify installation
75
+ ```
76
+
77
+ Allowed types are `feat`, `fix`, `perf`, `revert`, `docs`, `style`,
78
+ `refactor`, `test`, `build`, `ci`, and `chore`. Scope is optional.
79
+ Use `!` before the colon for breaking changes and explain the migration in the
80
+ PR body. Choose the type for the actual change, since release tooling uses it.
81
+
82
+ The `conventional-commit` check uses
83
+ [amannn/action-semantic-pull-request](https://github.com/amannn/action-semantic-pull-request).
84
+ It reads PR metadata, including for forks, without checking out contributor code.
85
+ If it fails on a title, rename the PR; the edited event reruns the check.
86
+ Keep the existing PR and commits. Work-in-progress commits need not be rewritten.
87
+
88
+ Use **Squash and merge**, with the PR title as the commit title. Check the final
89
+ message before merging, including single-commit PRs, and preserve any
90
+ `BREAKING CHANGE:` explanation in the body. The repository's squash defaults
91
+ support this, but a maintainer can still edit the final message.
92
+ Release Please turns these commits into a release PR containing the version,
93
+ changelog, and lockfile update. Merging that PR authorizes PyPI publication after
94
+ CI. See [RELEASING.md](RELEASING.md) for the version rules and publishing.
95
+
96
+ ## Shared instructions for Codex and Claude
97
+
98
+ [AGENTS.md](AGENTS.md) is the canonical repository guidance. Codex reads it
99
+ directly; Claude reads the tracked `CLAUDE.md -> AGENTS.md` symlink. Edit
100
+ `AGENTS.md` once, including commit-policy changes, so both tools receive the
101
+ same instructions.
102
+
103
+ [dallay/agentsync](https://github.com/dallay/agentsync) manages that link through
104
+ [agentsync.toml](agentsync.toml). After cloning, or to repair a
105
+ missing or stale link, run these commands from the repository root with Node.js
106
+ 18+ and npm installed:
107
+
108
+ ```bash
109
+ npx --yes @dallay/agentsync@1.52.3 apply
110
+ npx --yes @dallay/agentsync@1.52.3 status
111
+ ```
112
+
113
+ The CLI version is pinned for reproducible setup. Review and update both commands
114
+ when upgrading AgentSync. The configuration disables managed gitignore changes
115
+ because we intentionally commit the relative link, following AgentSync's
116
+ [committed-destination workflow](https://dallay.github.io/agentsync/guides/gitignore-team-workflows/).
117
+ Ordinary instruction edits propagate immediately through the link.
118
+
119
+ On native Windows, enable Developer Mode and Git symlink support
120
+ (`git config core.symlinks true`), then run `apply` to repair a checkout that
121
+ materialized the link as plain text. Alternatively, use WSL for a checkout in
122
+ the Linux filesystem. See the
123
+ [Windows setup guide](https://dallay.github.io/agentsync/guides/windows-symlink-setup/).
124
+ If AgentSync backs up an existing `CLAUDE.md`, review and preserve any unique
125
+ guidance in `AGENTS.md`; do not commit the backup as another instruction source.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pytest-selective
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Explainable Python test impact analysis: select affected pytest files from Git changes
5
5
  Project-URL: Homepage, https://github.com/gigaverse-app/pytest-selective
6
6
  Project-URL: Documentation, https://github.com/gigaverse-app/pytest-selective/blob/main/docs/README.md
@@ -33,11 +33,6 @@ Description-Content-Type: text/markdown
33
33
 
34
34
  **Run affected Python tests. See why they matter.**
35
35
 
36
- Our [Windows critical-path experiment](docs/benchmarks/2026-10-23-windows-saleor.md)
37
- cut the full validation gate from **249s to 185s** against a fresh unchanged
38
- control, preserving every existing case, the full platform matrix and coverage.
39
- The report separates test execution from runner variation and includes raw evidence.
40
-
41
36
  [![CI](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml)
42
37
  [![PyPI](https://img.shields.io/pypi/v/pytest-selective)](https://pypi.org/project/pytest-selective/)
43
38
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white)](https://github.com/gigaverse-app/pytest-selective/blob/main/pyproject.toml)
@@ -46,11 +41,6 @@ The report separates test execution from runner variation and includes raw evide
46
41
  [![Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/gigaverse-app/pytest-selective/blob/main/LICENSE)
47
42
  [![Agent skill](https://img.shields.io/badge/Agent_Skill-ready-2563EB)](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/agents.md)
48
43
 
49
- **Our README CI used 92.3% less runner time: 627s → 48s.** Elapsed time fell
50
- from 211s to 26s, with docs, routing and package checks preserved. One successful
51
- same-revision pair, not a universal speedup.
52
- [Inspect the runs and raw evidence](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/benchmarks/2026-10-22-routing.md).
53
-
54
44
  pytest-selective is a **Python test impact analysis** tool for incremental testing
55
45
  with pytest. It follows dependencies through both sides of a Git change, selects
56
46
  the affected test files, and explains the result. Use it directly as a pytest
@@ -74,6 +64,29 @@ used **49 instead of 105 runner-seconds (53.3% less)** while keeping quality,
74
64
  routing and package checks. Its reports now compute dependency critical paths
75
65
  and slack. [See the source runs and method](https://github.com/gigaverse-app/ci-esta/blob/main/docs/benchmarks/2026-10-23-toolkit.md).
76
66
 
67
+ ## Choose how to use it
68
+
69
+ | You want to… | Use | What it saves |
70
+ | --- | --- | --- |
71
+ | Test local edits with your existing pytest command | `uv add --dev pytest-selective`, then `uv run pytest --selective` | Unaffected test execution; staged, unstaged and untracked changes are included |
72
+ | Avoid expensive collection and application imports | `pytest-selective run --config .github/test-impact.json -- -q` | Collection/imports for unaffected files as well as execution |
73
+ | Plan affected files in GitHub Actions | `gigaverse-app/pytest-selective@main` | Plans before installing your application |
74
+ | Keep whole-suite coverage or conformance checks | `gigaverse-app/pytest-selective/plan-lanes@main` | Entire unaffected jobs, including their services and setup |
75
+ | Check assumptions about JSON, templates and other runtime inputs | Optional file-read recorder and dependency audit | Exposes observed reads missing from the declared graph |
76
+ | Keep selection narrow as the project grows | Explanations, startup-floor budgets, expansion and isolation guards | Makes broad new fixture/import dependencies visible |
77
+
78
+ Start with [local pytest](docs/local-development.md), [the complete CI recipe](docs/ci.md),
79
+ or [dependency audits and hygiene](docs/selection-health.md). The native plugin
80
+ collects normally; the pre-collection runner and CI planner can avoid that cost.
81
+ Keep full checkpoints and use complete lanes when partial suites cannot satisfy
82
+ your coverage contract.
83
+
84
+ **Public-path availability:** root and short action paths are new on `main`;
85
+ existing `v0.1` releases predate them. Evaluate with `@main`, or pin a reviewed
86
+ commit containing the public `action.yml`. Adopt a compatible release tag after
87
+ it includes these paths. Existing `.github/actions/...` paths remain supported.
88
+ [Public action API](docs/actions.md).
89
+
77
90
  ## Have your agent set it up
78
91
 
79
92
  Paste this into your coding agent in the Python project you want to improve:
@@ -154,7 +167,8 @@ complete requested suite. [Plugin configuration and limits](docs/local-developme
154
167
  For pre-collection selection, use `pytest-selective run`; for CI jobs with
155
168
  expensive setup or whole-suite evidence requirements, use lane selection.
156
169
 
157
- Requires **Python 3.11+, Git 2.24+, and uv**. Use a planner Python version at
170
+ Requires **Python 3.11+ and Git 2.24+**. The examples use uv; the native plugin
171
+ also works in your existing pytest environment. Use a planner Python version at
158
172
  least as new as your source syntax; the CI action uses Python 3.14. Your test
159
173
  runtime can use a different Python version when planning runs separately.
160
174
  The optional audit recorder requires Python 3.11+ in the test environment.
@@ -190,8 +204,8 @@ For source development, GitHub installation is also available:
190
204
  pip install "pytest-selective @ git+https://github.com/gigaverse-app/pytest-selective.git"
191
205
  ```
192
206
 
193
- Use compatible package ranges and `@v0.1` Actions tags in CI; lockfiles retain
194
- exact resolved artifacts. Then follow the
207
+ Use compatible package ranges; lockfiles retain exact resolved artifacts.
208
+ For action-path availability and release pins, see [the action API](docs/actions.md). Then follow the
195
209
  [configuration walkthrough](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/configuration.md)
196
210
  to declare module roots, test roots, collection-policy fingerprints, and non-Python inputs.
197
211
 
@@ -219,7 +233,7 @@ skip pytest, because invoking pytest without paths runs the whole suite.
219
233
  | Undeclared runtime reads | An opt-in pytest recorder and audit command |
220
234
 
221
235
  The CLI emits JSON for your runner. The
222
- [composite action](https://github.com/gigaverse-app/pytest-selective/blob/main/.github/actions/test-impact/action.yml)
236
+ [composite action](https://github.com/gigaverse-app/pytest-selective/blob/main/test-impact/action.yml)
223
237
  adds caching and falls back to complete test roots on operational planning
224
238
  failures. Invalid dependency declarations fail with a diagnostic that must be fixed.
225
239
 
@@ -244,9 +258,9 @@ and evidence checks.
244
258
  ## Choose the right tool
245
259
 
246
260
  [pytest-impacted](https://github.com/promptromp/pytest-impacted) offers a pytest-native
247
- `--impacted` workflow, including working-tree changes. pytest-selective focuses on
248
- committed revisions, inspectable JSON plans, runtime dependency audits, and
249
- planning before application startup. Both use static dependency analysis; choose
261
+ `--impacted` workflow, including working-tree changes. pytest-selective supports the same local edit/test loop and also offers
262
+ inspectable JSON plans, runtime dependency audits, and planning before application
263
+ startup. Both use static dependency analysis; choose
250
264
  based on your workflow, and validate selection against your own suite.
251
265
  See the [lessons from pytest-impacted](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/pytest-impacted.md)
252
266
  for portability and Git-resolution improvements adopted from that comparison.
@@ -280,7 +294,7 @@ optional; pytest-selective does not depend on it.</sub>
280
294
 
281
295
  See the [CI toolkit integration](docs/ci-toolkit.md) for lane selection, validated
282
296
  environment caches, required gates and real dependency critical-path reports.
283
- # Optimize the work that still has to run
297
+ ## Optimize the work that still has to run
284
298
 
285
299
  Selection and execution solve different parts of slow CI. Once selection keeps
286
300
  the required tests, use [CI-esta's critical-path report](https://github.com/gigaverse-app/ci-esta/blob/main/docs/critical-path-optimizations.md)
@@ -2,11 +2,6 @@
2
2
 
3
3
  **Run affected Python tests. See why they matter.**
4
4
 
5
- Our [Windows critical-path experiment](docs/benchmarks/2026-10-23-windows-saleor.md)
6
- cut the full validation gate from **249s to 185s** against a fresh unchanged
7
- control, preserving every existing case, the full platform matrix and coverage.
8
- The report separates test execution from runner variation and includes raw evidence.
9
-
10
5
  [![CI](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml)
11
6
  [![PyPI](https://img.shields.io/pypi/v/pytest-selective)](https://pypi.org/project/pytest-selective/)
12
7
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white)](https://github.com/gigaverse-app/pytest-selective/blob/main/pyproject.toml)
@@ -15,11 +10,6 @@ The report separates test execution from runner variation and includes raw evide
15
10
  [![Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/gigaverse-app/pytest-selective/blob/main/LICENSE)
16
11
  [![Agent skill](https://img.shields.io/badge/Agent_Skill-ready-2563EB)](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/agents.md)
17
12
 
18
- **Our README CI used 92.3% less runner time: 627s → 48s.** Elapsed time fell
19
- from 211s to 26s, with docs, routing and package checks preserved. One successful
20
- same-revision pair, not a universal speedup.
21
- [Inspect the runs and raw evidence](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/benchmarks/2026-10-22-routing.md).
22
-
23
13
  pytest-selective is a **Python test impact analysis** tool for incremental testing
24
14
  with pytest. It follows dependencies through both sides of a Git change, selects
25
15
  the affected test files, and explains the result. Use it directly as a pytest
@@ -43,6 +33,29 @@ used **49 instead of 105 runner-seconds (53.3% less)** while keeping quality,
43
33
  routing and package checks. Its reports now compute dependency critical paths
44
34
  and slack. [See the source runs and method](https://github.com/gigaverse-app/ci-esta/blob/main/docs/benchmarks/2026-10-23-toolkit.md).
45
35
 
36
+ ## Choose how to use it
37
+
38
+ | You want to… | Use | What it saves |
39
+ | --- | --- | --- |
40
+ | Test local edits with your existing pytest command | `uv add --dev pytest-selective`, then `uv run pytest --selective` | Unaffected test execution; staged, unstaged and untracked changes are included |
41
+ | Avoid expensive collection and application imports | `pytest-selective run --config .github/test-impact.json -- -q` | Collection/imports for unaffected files as well as execution |
42
+ | Plan affected files in GitHub Actions | `gigaverse-app/pytest-selective@main` | Plans before installing your application |
43
+ | Keep whole-suite coverage or conformance checks | `gigaverse-app/pytest-selective/plan-lanes@main` | Entire unaffected jobs, including their services and setup |
44
+ | Check assumptions about JSON, templates and other runtime inputs | Optional file-read recorder and dependency audit | Exposes observed reads missing from the declared graph |
45
+ | Keep selection narrow as the project grows | Explanations, startup-floor budgets, expansion and isolation guards | Makes broad new fixture/import dependencies visible |
46
+
47
+ Start with [local pytest](docs/local-development.md), [the complete CI recipe](docs/ci.md),
48
+ or [dependency audits and hygiene](docs/selection-health.md). The native plugin
49
+ collects normally; the pre-collection runner and CI planner can avoid that cost.
50
+ Keep full checkpoints and use complete lanes when partial suites cannot satisfy
51
+ your coverage contract.
52
+
53
+ **Public-path availability:** root and short action paths are new on `main`;
54
+ existing `v0.1` releases predate them. Evaluate with `@main`, or pin a reviewed
55
+ commit containing the public `action.yml`. Adopt a compatible release tag after
56
+ it includes these paths. Existing `.github/actions/...` paths remain supported.
57
+ [Public action API](docs/actions.md).
58
+
46
59
  ## Have your agent set it up
47
60
 
48
61
  Paste this into your coding agent in the Python project you want to improve:
@@ -123,7 +136,8 @@ complete requested suite. [Plugin configuration and limits](docs/local-developme
123
136
  For pre-collection selection, use `pytest-selective run`; for CI jobs with
124
137
  expensive setup or whole-suite evidence requirements, use lane selection.
125
138
 
126
- Requires **Python 3.11+, Git 2.24+, and uv**. Use a planner Python version at
139
+ Requires **Python 3.11+ and Git 2.24+**. The examples use uv; the native plugin
140
+ also works in your existing pytest environment. Use a planner Python version at
127
141
  least as new as your source syntax; the CI action uses Python 3.14. Your test
128
142
  runtime can use a different Python version when planning runs separately.
129
143
  The optional audit recorder requires Python 3.11+ in the test environment.
@@ -159,8 +173,8 @@ For source development, GitHub installation is also available:
159
173
  pip install "pytest-selective @ git+https://github.com/gigaverse-app/pytest-selective.git"
160
174
  ```
161
175
 
162
- Use compatible package ranges and `@v0.1` Actions tags in CI; lockfiles retain
163
- exact resolved artifacts. Then follow the
176
+ Use compatible package ranges; lockfiles retain exact resolved artifacts.
177
+ For action-path availability and release pins, see [the action API](docs/actions.md). Then follow the
164
178
  [configuration walkthrough](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/configuration.md)
165
179
  to declare module roots, test roots, collection-policy fingerprints, and non-Python inputs.
166
180
 
@@ -188,7 +202,7 @@ skip pytest, because invoking pytest without paths runs the whole suite.
188
202
  | Undeclared runtime reads | An opt-in pytest recorder and audit command |
189
203
 
190
204
  The CLI emits JSON for your runner. The
191
- [composite action](https://github.com/gigaverse-app/pytest-selective/blob/main/.github/actions/test-impact/action.yml)
205
+ [composite action](https://github.com/gigaverse-app/pytest-selective/blob/main/test-impact/action.yml)
192
206
  adds caching and falls back to complete test roots on operational planning
193
207
  failures. Invalid dependency declarations fail with a diagnostic that must be fixed.
194
208
 
@@ -213,9 +227,9 @@ and evidence checks.
213
227
  ## Choose the right tool
214
228
 
215
229
  [pytest-impacted](https://github.com/promptromp/pytest-impacted) offers a pytest-native
216
- `--impacted` workflow, including working-tree changes. pytest-selective focuses on
217
- committed revisions, inspectable JSON plans, runtime dependency audits, and
218
- planning before application startup. Both use static dependency analysis; choose
230
+ `--impacted` workflow, including working-tree changes. pytest-selective supports the same local edit/test loop and also offers
231
+ inspectable JSON plans, runtime dependency audits, and planning before application
232
+ startup. Both use static dependency analysis; choose
219
233
  based on your workflow, and validate selection against your own suite.
220
234
  See the [lessons from pytest-impacted](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/pytest-impacted.md)
221
235
  for portability and Git-resolution improvements adopted from that comparison.
@@ -249,7 +263,7 @@ optional; pytest-selective does not depend on it.</sub>
249
263
 
250
264
  See the [CI toolkit integration](docs/ci-toolkit.md) for lane selection, validated
251
265
  environment caches, required gates and real dependency critical-path reports.
252
- # Optimize the work that still has to run
266
+ ## Optimize the work that still has to run
253
267
 
254
268
  Selection and execution solve different parts of slow CI. Once selection keeps
255
269
  the required tests, use [CI-esta's critical-path report](https://github.com/gigaverse-app/ci-esta/blob/main/docs/critical-path-optimizations.md)