Skip to content

Commit 9b3a1b1

Browse files
svelderrainruizGitHub Copilot
andauthored
Route Validate by change scope (#892) (#893)
* Route Validate by change scope #892 * Address validate scope review feedback #892 * Limit validate workflow token permissions #892 --------- Co-authored-by: GitHub Copilot <copilot@users.noreply.github.com>
1 parent 2880308 commit 9b3a1b1

8 files changed

Lines changed: 944 additions & 16 deletions

.github/workflows/validate.yml

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -376,26 +376,105 @@ jobs:
376376
)
377377
$lines -join "`n" | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
378378
}
379+
validate-scope-plan:
380+
needs: smoke-gate
381+
if: needs.smoke-gate.outputs.skip != 'true'
382+
runs-on: ubuntu-latest
383+
permissions:
384+
contents: read
385+
pull-requests: read
386+
outputs:
387+
scope_mode: ${{ steps.plan.outputs.scope_mode }}
388+
scope_category: ${{ steps.plan.outputs.scope_category }}
389+
run_fixtures: ${{ steps.plan.outputs.run_fixtures }}
390+
fixtures_reason: ${{ steps.plan.outputs.fixtures_reason }}
391+
run_bundle_certification: ${{ steps.plan.outputs.run_bundle_certification }}
392+
bundle_certification_reason: ${{ steps.plan.outputs.bundle_certification_reason }}
393+
run_vi_history: ${{ steps.plan.outputs.run_vi_history }}
394+
vi_history_reason: ${{ steps.plan.outputs.vi_history_reason }}
395+
steps:
396+
- uses: actions/checkout@v5
397+
with:
398+
fetch-depth: 0
399+
400+
- name: Resolve Validate scope plan
401+
id: plan
402+
shell: pwsh
403+
env:
404+
VALIDATE_EVENT_NAME: ${{ github.event_name }}
405+
VALIDATE_REPOSITORY: ${{ github.repository }}
406+
VALIDATE_PR_NUMBER: ${{ github.event.pull_request.number || '' }}
407+
VALIDATE_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || '' }}
408+
VALIDATE_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }}
409+
VALIDATE_BASE_REF: ${{ github.base_ref || github.event.merge_group.base_ref || '' }}
410+
VALIDATE_HEAD_REF: ${{ github.head_ref || '' }}
411+
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
412+
GH_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
413+
run: |
414+
$resultsRoot = 'tests/results/_agent/validate-scope-plan'
415+
New-Item -ItemType Directory -Path $resultsRoot -Force | Out-Null
416+
$planPath = Join-Path $resultsRoot 'validate-scope-plan.json'
417+
pwsh -NoLogo -NoProfile -File tools/Resolve-ValidateScopePlan.ps1 `
418+
-EventName $env:VALIDATE_EVENT_NAME `
419+
-Repository $env:VALIDATE_REPOSITORY `
420+
-PullRequestNumber $env:VALIDATE_PR_NUMBER `
421+
-BaseSha $env:VALIDATE_BASE_SHA `
422+
-HeadSha $env:VALIDATE_HEAD_SHA `
423+
-BaseRef $env:VALIDATE_BASE_REF `
424+
-HeadRef $env:VALIDATE_HEAD_REF `
425+
-GitHubOutputPath $env:GITHUB_OUTPUT `
426+
-StepSummaryPath $env:GITHUB_STEP_SUMMARY `
427+
-JsonPath $planPath
428+
429+
- name: Upload Validate scope plan artifact
430+
if: always()
431+
uses: actions/upload-artifact@v5
432+
with:
433+
name: validate-scope-plan
434+
path: tests/results/_agent/validate-scope-plan/validate-scope-plan.json
435+
if-no-files-found: error
379436
fixtures:
437+
needs: [smoke-gate, lint, validate-scope-plan]
438+
if: needs.smoke-gate.outputs.skip != 'true'
380439
runs-on: [self-hosted, Windows, X64]
440+
permissions:
441+
contents: read
381442
env:
382443
FAIL_ON_NEW_STRUCTURAL: 'true'
383444
SUMMARY_VERBOSE: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.summary-verbose || 'false' }}
445+
VALIDATE_SCOPE_RUN_FIXTURES: ${{ needs.validate-scope-plan.outputs.run_fixtures }}
446+
VALIDATE_SCOPE_FIXTURES_REASON: ${{ needs.validate-scope-plan.outputs.fixtures_reason }}
447+
VALIDATE_SCOPE_CATEGORY: ${{ needs.validate-scope-plan.outputs.scope_category }}
384448
steps:
449+
- name: Append fixture lane plan
450+
shell: pwsh
451+
run: |
452+
if ($env:GITHUB_STEP_SUMMARY) {
453+
$lines = @(
454+
'### Fixtures',
455+
'',
456+
('- scope_category: `{0}`' -f $env:VALIDATE_SCOPE_CATEGORY),
457+
('- run_fixtures: `{0}`' -f $env:VALIDATE_SCOPE_RUN_FIXTURES),
458+
('- fixtures_reason: `{0}`' -f $env:VALIDATE_SCOPE_FIXTURES_REASON)
459+
)
460+
$lines -join "`n" | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
461+
}
385462
- uses: actions/checkout@v5
463+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
386464
- name: Wire Probe (J1)
387-
if: '${{ vars.WIRE_PROBES != ''0'' }}'
465+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true' && vars.WIRE_PROBES != '0'
388466
uses: ./.github/actions/wire-probe
389467
with:
390468
phase: J1
391469
results-dir: tests/results
392470
- name: Wire Probe (J2)
393-
if: '${{ vars.WIRE_PROBES != ''0'' }}'
471+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true' && vars.WIRE_PROBES != '0'
394472
uses: ./.github/actions/wire-probe
395473
with:
396474
phase: J2
397475
results-dir: tests/results
398476
- name: Run fixture validator (JSON)
477+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
399478
shell: pwsh
400479
run: |
401480
$ErrorActionPreference = 'Stop'
@@ -411,6 +490,7 @@ jobs:
411490
exit 1
412491
}
413492
- name: Restore previous fixture validation snapshot (cache)
493+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
414494
id: restore_prev_fixture_validation
415495
uses: actions/cache/restore@v4
416496
with:
@@ -419,7 +499,7 @@ jobs:
419499
restore-keys: |
420500
fixture-validation-
421501
- name: Compute delta vs previous snapshot
422-
if: steps.restore_prev_fixture_validation.outputs.cache-hit == 'true'
502+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true' && steps.restore_prev_fixture_validation.outputs.cache-hit == 'true'
423503
shell: pwsh
424504
run: |
425505
Write-Host 'Previous snapshot restored. Computing delta.'
@@ -434,27 +514,29 @@ jobs:
434514
}
435515
}
436516
- name: Validate delta JSON schema (basic)
437-
if: steps.restore_prev_fixture_validation.outputs.cache-hit == 'true' && hashFiles('fixture-validation-delta.json') != ''
517+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true' && steps.restore_prev_fixture_validation.outputs.cache-hit == 'true' && hashFiles('fixture-validation-delta.json') != ''
438518
shell: pwsh
439519
run: |
440520
pwsh -File tools/Test-FixtureValidationDeltaSchema.ps1 -DeltaJsonPath fixture-validation-delta.json
441521
- name: Lite schema validate (delta)
442-
if: steps.restore_prev_fixture_validation.outputs.cache-hit == 'true' && hashFiles('fixture-validation-delta.json') != ''
522+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true' && steps.restore_prev_fixture_validation.outputs.cache-hit == 'true' && hashFiles('fixture-validation-delta.json') != ''
443523
shell: pwsh
444524
run: |
445525
pwsh -File tools/Invoke-JsonSchemaLite.ps1 -JsonPath fixture-validation-delta.json -SchemaPath docs/schemas/fixture-validation-delta-v1.schema.json
446526
- name: Upload fixture validation delta JSON
447-
if: steps.restore_prev_fixture_validation.outputs.cache-hit == 'true' && hashFiles('fixture-validation-delta.json') != ''
527+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true' && steps.restore_prev_fixture_validation.outputs.cache-hit == 'true' && hashFiles('fixture-validation-delta.json') != ''
448528
uses: actions/upload-artifact@v5
449529
with:
450530
name: validate-fixture-validation-delta-json
451531
path: fixture-validation-delta.json
452532
- name: Upload fixture validation JSON
533+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
453534
uses: actions/upload-artifact@v5
454535
with:
455536
name: validate-fixture-validation-json
456537
path: fixture-validation.json
457538
- name: Lite schema validate (snapshot)
539+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
458540
shell: pwsh
459541
run: |
460542
if (-not (Test-Path fixture-validation.json)) {
@@ -463,29 +545,32 @@ jobs:
463545
}
464546
pwsh -File tools/Invoke-JsonSchemaLite.ps1 -JsonPath fixture-validation.json -SchemaPath docs/schemas/fixture-manifest-v1.schema.json
465547
- name: Append fixture summary
548+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
466549
shell: pwsh
467550
run: pwsh -File tools/Write-FixtureValidationSummary.ps1 -ValidationJson fixture-validation.json -DeltaJson fixture-validation-delta.json
468551
- name: Write fixture summary file
469-
if: always()
552+
if: always() && env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
470553
shell: pwsh
471554
run: pwsh -File tools/Write-FixtureValidationSummary.ps1 -ValidationJson fixture-validation.json -DeltaJson fixture-validation-delta.json -SummaryPath fixture-summary.md
472555
- name: Upload fixture summary artifact
473-
if: always() && hashFiles('fixture-summary.md') != ''
556+
if: always() && env.VALIDATE_SCOPE_RUN_FIXTURES == 'true' && hashFiles('fixture-summary.md') != ''
474557
uses: actions/upload-artifact@v5
475558
with:
476559
name: fixture-validation-summary
477560
path: fixture-summary.md
478561
- name: Save current snapshot to cache
562+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
479563
uses: actions/cache/save@v4
480564
with:
481565
path: fixture-validation.json
482566
key: fixture-validation-${{ github.sha }}
483567
- name: Copy snapshot for next run reference
568+
if: env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
484569
shell: pwsh
485570
run: Copy-Item -LiteralPath fixture-validation.json -Destination fixture-validation-prev.json -Force
486571

487572
- name: Agent wait summary (notice-only)
488-
if: always()
573+
if: always() && env.VALIDATE_SCOPE_RUN_FIXTURES == 'true'
489574
uses: ./.github/actions/agent-wait-post
490575
with:
491576
results-dir: tests/results
@@ -895,8 +980,10 @@ jobs:
895980
if-no-files-found: warn
896981

897982
comparevi-history-bundle-certification:
898-
needs: [smoke-gate, lint, fixtures, session-index, session-index-v2-contract]
899-
if: needs.smoke-gate.outputs.skip != 'true'
983+
needs: [smoke-gate, lint, validate-scope-plan, session-index, session-index-v2-contract]
984+
if: >
985+
needs.smoke-gate.outputs.skip != 'true' &&
986+
needs.validate-scope-plan.outputs.run_bundle_certification == 'true'
900987
runs-on: ubuntu-latest
901988
permissions:
902989
contents: read
@@ -974,7 +1061,7 @@ jobs:
9741061
if-no-files-found: error
9751062

9761063
vi-history-scenarios-plan:
977-
needs: [smoke-gate, lint, fixtures, session-index, session-index-v2-contract]
1064+
needs: [smoke-gate, lint, validate-scope-plan, session-index, session-index-v2-contract]
9781065
if: needs.smoke-gate.outputs.skip != 'true'
9791066
runs-on: ubuntu-latest
9801067
permissions:
@@ -998,20 +1085,26 @@ jobs:
9981085
VALIDATE_HISTORY_SCENARIO_SET: ${{ github.event.inputs.history_scenario_set }}
9991086
VALIDATE_ALLOW_NONCANONICAL: ${{ github.event.inputs.allow_noncanonical_vi_history }}
10001087
VALIDATE_ALLOW_NONCANONICAL_HISTORY_CORE: ${{ github.event.inputs.allow_noncanonical_history_core }}
1088+
VALIDATE_SCOPE_RUN_VI_HISTORY: ${{ needs.validate-scope-plan.outputs.run_vi_history }}
1089+
VALIDATE_SCOPE_VI_HISTORY_REASON: ${{ needs.validate-scope-plan.outputs.vi_history_reason }}
10011090
run: |
10021091
$resultsRoot = 'tests/results/_agent/vi-history-dispatch'
10031092
New-Item -ItemType Directory -Path $resultsRoot -Force | Out-Null
10041093
$planPath = Join-Path $resultsRoot 'validate-vi-history-dispatch-plan.json'
10051094
$isForkRepository = "$env:VALIDATE_IS_FORK" -eq 'true'
10061095
$allowNonCanonical = "$env:VALIDATE_ALLOW_NONCANONICAL" -eq 'true'
10071096
$allowNonCanonicalHistoryCore = "$env:VALIDATE_ALLOW_NONCANONICAL_HISTORY_CORE" -eq 'true'
1097+
$enableScopedExecution = "$env:VALIDATE_SCOPE_RUN_VI_HISTORY" -eq 'true'
10081098
pwsh -NoLogo -NoProfile -File tools/Resolve-ValidateVIHistoryDispatchPlan.ps1 `
10091099
-EventName $env:VALIDATE_EVENT_NAME `
10101100
-Repository $env:VALIDATE_REPOSITORY `
10111101
-IsForkRepository:$isForkRepository `
10121102
-HistoryScenarioSet $env:VALIDATE_HISTORY_SCENARIO_SET `
10131103
-AllowNonCanonical:$allowNonCanonical `
10141104
-AllowNonCanonicalHistoryCore:$allowNonCanonicalHistoryCore `
1105+
-EnableScopedExecution:$enableScopedExecution `
1106+
-ScopedSkipReason $env:VALIDATE_SCOPE_VI_HISTORY_REASON `
1107+
-ScopedHistoryScenarioSet 'smoke' `
10151108
-GitHubOutputPath $env:GITHUB_OUTPUT `
10161109
-StepSummaryPath $env:GITHUB_STEP_SUMMARY `
10171110
-JsonPath $planPath
@@ -1025,7 +1118,7 @@ jobs:
10251118
if-no-files-found: error
10261119

10271120
vi-history-scenarios-windows:
1028-
needs: [smoke-gate, lint, fixtures, session-index, session-index-v2-contract, vi-history-scenarios-plan, vi-history-scenarios-linux]
1121+
needs: [smoke-gate, lint, session-index, session-index-v2-contract, vi-history-scenarios-plan, vi-history-scenarios-linux]
10291122
if: >
10301123
needs.smoke-gate.outputs.skip != 'true' &&
10311124
needs.vi-history-scenarios-plan.outputs.execute_lanes == 'true'
@@ -1137,7 +1230,7 @@ jobs:
11371230
if-no-files-found: warn
11381231

11391232
vi-history-scenarios-linux:
1140-
needs: [smoke-gate, lint, fixtures, session-index, session-index-v2-contract, vi-history-scenarios-plan]
1233+
needs: [smoke-gate, lint, session-index, session-index-v2-contract, vi-history-scenarios-plan]
11411234
if: needs.smoke-gate.outputs.skip != 'true'
11421235
runs-on: ubuntu-latest
11431236
permissions:

docs/DEVELOPER_GUIDE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,21 @@ For Docker/Desktop VI history validation, run fast-loop lanes explicitly:
298298
commits land on `develop`/`main`.
299299
- Keep PRs focused and include the standing issue reference (`#<number>`) in the commit subject and PR description.
300300
- Ensure required checks (`validate`, `fixtures`, `session-index`) are green before merging; rerun as needed.
301+
- `Validate` now computes a `validate-scope-plan` artifact before the heavy lanes fan out.
302+
Standard `pull_request` and `merge_group` runs classify changed paths with an allow-list into:
303+
`docs-metadata-only`, `tests-only`, `tools-policy-only`, `ci-control-plane`, `mixed-lightweight`, `compare-engine-history`,
304+
`docker-vi-history`, plus conservative fallbacks (`mixed-runtime`, `unclassified`).
305+
Manual `workflow_dispatch` stays explicit (`manual-full`) and `push` keeps the default post-merge full validation shape.
306+
- Scoped skip surfaces:
307+
Required checks stay deterministic: `fixtures` and `vi-history-scenarios-linux` still report status for lightweight
308+
scopes, but their expensive steps no-op when routing says the lane is out of scope.
309+
`fixtures` heavy work only runs for `compare-engine-history`, `mixed-runtime`, `unclassified`, and explicit full-validation modes.
310+
`comparevi-history-bundle-certification` follows the same routing.
311+
`vi-history-scenarios-*` runs for `compare-engine-history`, `docker-vi-history`, `mixed-runtime`, `unclassified`, and
312+
explicit manual dispatches; the final VI-history plan still honors `history_scenario_set`.
313+
- Machine-readable routing evidence is written to
314+
`tests/results/_agent/validate-scope-plan/validate-scope-plan.json` and summarized in the Validate step summary so
315+
reviewers can see why heavy lanes were bypassed.
301316
- On `develop`, Copilot review is expected on ready PRs. Use **Draft PR** state as the explicit escape hatch when you do
302317
not want Copilot review to run yet. Ready `develop` PRs also need the `agent-review-policy` check to turn green after
303318
either:

0 commit comments

Comments
 (0)