Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 57 additions & 50 deletions .github/workflows/batch-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -270,20 +270,27 @@ jobs:
'pipreqs summary not generated.' | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Encoding utf8 -Append
}

- name: Check Miniconda availability (for downstream !cancelled() gating)
# derived requirement (item 7 scoping-pass follow-on): Miniconda installs to a SHARED,
# machine-wide path (%PUBLIC%\Documents\Miniconda3), not per-test-directory -- see the
# :tci_both_failed CLAUDE.md entry. This is a single, cheap Test-Path (no execution of
# run_setup.bat, no network) that downstream !cancelled()-converted steps consult before
# attempting their own conda-dependent selfapps script, so a genuine "Miniconda itself
# failed to install" failure produces one clean skip per step instead of dozens of
# steps EACH redundantly retrying a real (up to 60-90 min per HP_INSTALLER_TIMEOUT)
# Miniconda install. !cancelled() so it still runs even when Bootstrap environment
# itself failed, but is skipped (like every other step here) if the run is cancelled.
# Checks both condabin\conda.bat and the Scripts\conda.bat fallback -- matches
# run_setup.bat's own :select_conda_bat (CONDA_MAIN/CONDA_ALT) and the "Validate restored
# conda binary" step above, so an install that only landed via the fallback path (a real,
# accepted-elsewhere possibility) isn't misreported as unavailable here.
- name: Check Miniconda availability (diagnostic only -- no longer gates downstream steps)
# derived requirement (found 2026-07-27, real-CI-confirmed): this check's own premise was
# wrong for THIS repo's own CI shape. It was designed on the assumption that the earlier
# "Bootstrap environment (run_setup.bat)" step (matrix.mode == conda-full, HP_FORCE_CONDA_
# ONLY=1) would itself perform the first real Miniconda install, so gating downstream
# conda-dependent steps on "is conda already on disk" would only ever skip in the rare
# case that install genuinely failed. In reality that step runs against THIS repo's own
# root (no loose .py files -- it's testing the empty-repo/no_python_files graceful-exit
# path, not a real app), so it NEVER installs Miniconda -- and because every downstream
# selfapps step capable of performing the FIRST real install was ALSO gated on this same
# check, the conda-full lane could never bootstrap conda for the first time again: a
# circular self-skip. Confirmed via the GitHub Actions API against two real runs (efd7a5c
# and fd7a046, PR #390) -- ~27 real/conda-full-only self-tests silently "skipped" every
# single run, at the exact same timestamp, with the job still reporting overall SUCCESS
# (skipped steps don't fail a job), so it merged without the coverage loss ever surfacing.
# Downstream !cancelled()-conditions were reverted to their pre-item-7 unconditional form
# (matrix.mode == 'conda-full', no conda_avail dependency) -- see CLAUDE.md Active Backlog
# for the follow-up: either wire this check in at a point where a real install has
# actually had a chance to happen, or remove it if the redundant-retry risk it was meant
# to prevent doesn't materialize in practice. The step itself is left in place (harmless,
# informational Write-Host only) since nothing currently consumes its output.
if: ${{ !cancelled() }}
id: conda_avail
shell: pwsh
Expand All @@ -295,38 +302,38 @@ jobs:
Write-Host "Miniconda available at shared path: $avail"

- name: "Self-test: empty repo behavior"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
shell: pwsh
run: |
& .\tests\selftests.ps1
Get-Content -LiteralPath tests\~selftest_empty\~empty_bootstrap.log -Tail 60 -ErrorAction SilentlyContinue

- name: "Self-test: single .py entry (CI-only)"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
env:
HP_CI_SKIP_ENV: '1'
shell: pwsh
run: |
& tests\selfapps_single.ps1

- name: "Self-test: entry selection (CI-only)"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
env:
HP_CI_SKIP_ENV: '1'
shell: pwsh
run: |
& tests\selfapps_entry.ps1

- name: "Self-test: isolation and directory integrity (CI-only)"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
env:
HP_CI_SKIP_ENV: '1'
shell: pwsh
run: |
& tests\selfapps_isolation.ps1

- name: "Self-test: env-name sanitization (leading hyphen)"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
shell: pwsh
run: |
& tests\selfapps_envname.ps1
Expand All @@ -341,7 +348,7 @@ jobs:
& tests\selfapps_size.ps1

- name: "Self-test: real env smoke (CI-only)"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
shell: pwsh
run: |
& tests\selfapps_envsmoke.ps1
Expand All @@ -368,51 +375,51 @@ jobs:
& tests\selfapps_dl_fallback.ps1

- name: "Self-test: requirements specifier coverage"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
shell: pwsh
run: |
& tests\selfapps_reqspec.ps1

- name: "Self-test: dep-check skip scenario (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_depcheck.ps1

- name: "Self-test: warnfix PASS scenario (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
env:
WARNFIX_SCENARIO: pass
shell: pwsh
run: |
& tests\selfapps_warnfix.ps1

- name: "Self-test: warnfix XFAIL scenario (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
env:
WARNFIX_SCENARIO: xfail
shell: pwsh
run: |
& tests\selfapps_warnfix.ps1

- name: "Self-test: warnfix REAL scenario - heuristic prevents warnfix (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
env:
WARNFIX_SCENARIO: real
shell: pwsh
run: |
& tests\selfapps_warnfix.ps1

- name: "Self-test: warnfix REAL_WARNFIX scenario - warnfix fixes non-heuristic dep (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
env:
WARNFIX_SCENARIO: real_warnfix
shell: pwsh
run: |
& tests\selfapps_warnfix.ps1

- name: "Self-test: warnfix REAL_WARNFIX_DELAYED scenario - warnfix processes delayed imports (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
env:
WARNFIX_SCENARIO: real_warnfix_delayed
shell: pwsh
Expand Down Expand Up @@ -547,13 +554,13 @@ jobs:
& tests\selfapps_pvw_idempotent.ps1

- name: "Self-test: pre-build collect-submodules double-gate (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_collect.ps1

- name: "Self-test: strict --hidden-import auto-recovery (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_hidden_import.ps1
Expand All @@ -562,7 +569,7 @@ jobs:
# auto-recovery loop to its 3-attempt cap without ever succeeding (its sibling above only
# covers the one-shot-recoverable success path).
- name: "Self-test: strict --hidden-import auto-recovery exhaustion (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_hidden_import_exhaust.ps1
Expand Down Expand Up @@ -673,97 +680,97 @@ jobs:
& tests\selfapps_interactive_stdin.ps1

- name: "Self-test: EXE smokerun XFAIL bad import (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_exefail.ps1

- name: "Self-test: PyInstaller build failure correctly reported, not masked (execfail, real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
env:
PYI_FAIL_SCENARIO: execfail
run: |
& tests\selfapps_pyinstaller_fail.ps1

- name: "Self-test: PyInstaller build failure correctly reported, not masked (output_vanish, real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
env:
PYI_FAIL_SCENARIO: output_vanish
run: |
& tests\selfapps_pyinstaller_fail.ps1

- name: "Self-test: no-EXE briefing is honest when the interpreter fallback also fails (execfail_runtimefail, real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
env:
PYI_FAIL_SCENARIO: execfail_runtimefail
run: |
& tests\selfapps_pyinstaller_fail.ps1

- name: "Self-test: REQ-021 py_compile pre-flight syntax error (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_preflight.ps1

- name: "Self-test: EXE smokerun XFAIL missing data file (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_exedata_fail.ps1

- name: "Self-test: EXE smokerun XFAIL dynamic import not bundled (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_exedyn_fail.ps1

- name: "Self-test: fast-path broken-EXE graceful fallback (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_exefastpath.ps1

- name: "Self-test: fail-fast probe -- fast-failure discard and alive-past-probe no-discard (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_failfast_probe.ps1

- name: "Self-test: post-execution checkpoint -- accept and decline (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_postexec_checkpoint.ps1

- name: "Self-test: super-user skip hooks (conda-full only)"
if: ${{ !cancelled() && matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true' }}
if: ${{ !cancelled() && matrix.mode == 'conda-full' }}
shell: pwsh
run: |
& tests\selfapps_skiphooks.ps1

- name: "Self-test: REQ-002 timed entry picker (conda-full only)"
if: ${{ !cancelled() && matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true' }}
if: ${{ !cancelled() && matrix.mode == 'conda-full' }}
shell: pwsh
run: |
& tests\selfapps_entry_picker.ps1

- name: "Self-test: REQ-009 cascade consent timed prompt (conda-full only)"
if: ${{ !cancelled() && matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true' }}
if: ${{ !cancelled() && matrix.mode == 'conda-full' }}
shell: pwsh
run: |
& tests\selfapps_cascade_timed.ps1

- name: "Test pandas/openpyxl heuristic (conda-full only)"
if: ${{ !cancelled() && matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true' }}
if: ${{ !cancelled() && matrix.mode == 'conda-full' }}
shell: pwsh
run: |
& tests\selfapps_pandas_excel.ps1

- name: "Test pip gap-fill safety net (conda-full only)"
if: ${{ !cancelled() && matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true' }}
if: ${{ !cancelled() && matrix.mode == 'conda-full' }}
shell: pwsh
run: |
& tests\selfapps_pipgap.ps1
Expand Down Expand Up @@ -897,31 +904,31 @@ jobs:
if (-not $pass) { Write-Host $outStr; exit 1 }

- name: "Self-test: runtime.txt write-back (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_runtime_writeback.ps1

- name: "Self-test: pyvisa NI-VISA detection (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_pyvisa.ps1

- name: "Self-test: pyproject.toml Python version precedence (real/conda-full only)"
if: ${{ !cancelled() && (matrix.mode == 'real' || (matrix.mode == 'conda-full' && steps.conda_avail.outputs.available == 'true')) }}
if: ${{ !cancelled() && (matrix.mode == 'real' || matrix.mode == 'conda-full') }}
shell: pwsh
run: |
& tests\selfapps_pyproject_precedence.ps1

- name: "Self-test: UX hardening (git config merge)"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
shell: pwsh
run: |
& tests\selfapps_ux_hardening.ps1

- name: "Self-test: REQ-007 system-Python build consent gate (non-conda-full)"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' && (matrix.mode != 'conda-full' || steps.conda_avail.outputs.available == 'true') }}
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
shell: pwsh
run: |
& tests\selfapps_sysbuild.ps1
Expand Down
Loading
Loading