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
96 changes: 59 additions & 37 deletions .github/workflows/batch-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -270,37 +270,6 @@ jobs:
'pipreqs summary not generated.' | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Encoding utf8 -Append
}

- 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
run: |
$condaMain = 'C:\Users\Public\Documents\Miniconda3\condabin\conda.bat'
$condaAlt = 'C:\Users\Public\Documents\Miniconda3\Scripts\conda.bat'
$avail = (Test-Path -LiteralPath $condaMain) -or (Test-Path -LiteralPath $condaAlt)
"available=$($avail.ToString().ToLowerInvariant())" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding ascii -Append
Write-Host "Miniconda available at shared path: $avail"

- name: "Self-test: empty repo behavior"
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
shell: pwsh
Expand Down Expand Up @@ -353,6 +322,58 @@ jobs:
run: |
& tests\selfapps_envsmoke.ps1

- name: "Check Miniconda availability (diagnostic only -- not yet wired to any if: condition)"
# derived requirement (moved here 2026-07-27, correcting item 7's original placement): this
# check previously ran right after "Bootstrap environment (run_setup.bat)" -- but that step
# runs against THIS repo's own root (no loose .py files, the empty-repo/no_python_files
# graceful-exit path), so it never installs Miniconda. Every downstream selfapps step
# capable of performing the FIRST real install was ALSO gated on that same premature check,
# producing a circular self-skip: confirmed via the GitHub Actions API against the CI runs
# for two real commits on PR #390 (efd7a5c, fd7a046) that ~27 real/conda-full-only self-
# tests silently "skipped" every run while the job still reported overall SUCCESS. See
# CLAUDE.md's Active Backlog item 7 for the full incident writeup and PR #391 for the
# revert that restored those steps to unconditional (matrix.mode == 'conda-full') form.
#
# This step is now positioned right after "Self-test: real env smoke (CI-only)"
# (selfapps_envsmoke.ps1) instead -- traced 2026-07-27 as the genuine first selfapps step
# that performs a REAL, unconditional run_setup.bat bootstrap under HP_FORCE_CONDA_ONLY=1
# (its own script comment: "FULL bootstrap here: do NOT set HP_CI_SKIP_ENV"; every earlier
# candidate -- selfapps_single.ps1/selfapps_entry.ps1/selfapps_isolation.ps1/
# selfapps_envname.ps1 -- sets HP_CI_SKIP_ENV=1 and never touches conda at all; selftests.ps1
# only replays a captured log; selfapps_size.ps1 is a static byte-size check). Under
# conda-full specifically, HP_FORCE_CONDA_ONLY=1 blocks every venv/system fallback envsmoke's
# own script would otherwise allow, so a nonzero exit there can only mean the conda install
# itself failed -- making this the correct point to sample "is conda now really available."
#
# Deliberately NOT yet wired to any if: condition in this same commit. This mechanism has
# already produced two real, independently-discovered bugs in quick succession (the
# premature-gate bug this comment describes, and a distinct CodeRabbit-caught wording slip
# on the PR that reverted it) -- landing the corrected POSITION on its own first, with zero
# steps depending on it yet, lets the very first conda-full run after this change prove
# (via the job summary / step logs) that `available` now correctly flips to 'true' once
# envsmoke's real install succeeds, before any gating logic is re-added in a follow-up PR.
if: ${{ !cancelled() && env.HP_CACHE_CORRUPTED != '1' }}
id: conda_avail
shell: pwsh
run: |
$condaMain = 'C:\Users\Public\Documents\Miniconda3\condabin\conda.bat'
$condaAlt = 'C:\Users\Public\Documents\Miniconda3\Scripts\conda.bat'
$avail = (Test-Path -LiteralPath $condaMain) -or (Test-Path -LiteralPath $condaAlt)
"available=$($avail.ToString().ToLowerInvariant())" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding ascii -Append
Write-Host "Miniconda available at shared path: $avail"
# derived requirement: this diagnostic's own output was previously observable
# (Write-Host + step output) but had no NDJSON row -- CodeRabbit flagged the gap on
# PR #394. Non-gating (pass is always true; this step never fails the job), so it is
# safe to record even before any downstream if: condition depends on it.
$row = [ordered]@{
id = 'diag.conda.available'
pass = $true
desc = 'Miniconda availability diagnostic (non-gating, unwired)'
details = [ordered]@{ available = $avail }
} | ConvertTo-Json -Compress -Depth 8
$row | Add-Content 'tests\~test-results.ndjson' -Encoding Ascii
$row | Add-Content 'ci_test_results.ndjson' -Encoding Ascii

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: "Self-test: uv contract assertions (contract-uv* only)"
if: ${{ matrix.mode == 'contract-uv' || matrix.mode == 'contract-uv-fail' }}
continue-on-error: true
Expand Down Expand Up @@ -1961,7 +1982,7 @@ jobs:
Add-Content $env:GITHUB_STEP_SUMMARY -Value "_tests\\~test-summary.txt not found_"
}

- name: Summarize self-tests (NDJSON Job Summary)
- name: Summarize self-tests (NDJSON -> Job Summary)
if: ${{ !cancelled() }}
uses: actions/github-script@v8
with:
Expand All @@ -1979,22 +2000,23 @@ jobs:

const passCt = rows.filter(r => r.pass === true).length;
const failCt = rows.filter(r => r.pass === false).length;
const unknownCt = rows.length - passCt - failCt;

// Prefer self.* and entry.* at the top
const rank = r => (r.id||'').startsWith('self.') || (r.id||'').startsWith('entry.') ? 0 : 1;
rows.sort((a,b) => rank(a) - rank(b) || String(a.id||'').localeCompare(String(b.id||'')));

const bullets = rows.map(r => {
const icon = r.pass === true ? '' : r.pass === false ? '' : '';
const desc = r.desc ? ` ${r.desc}` : '';
const icon = r.pass === true ? '[PASS]' : r.pass === false ? '[FAIL]' : '[-]';
const desc = r.desc ? ` -- ${r.desc}` : '';
return `${icon} ${r.id || '(no id)'}${desc}`;
});

const summary = core.summary;
await summary
.addHeading('Self-test results', 2)
.addList(bullets)
.addRaw(`\n**Totals:** PASS ${passCt} · FAIL ${failCt}\n`)
.addRaw(`\n**Totals:** PASS ${passCt} - FAIL ${failCt}${unknownCt > 0 ? ` - UNKNOWN ${unknownCt}` : ''}\n`)
.write();

// Optional tails (non-fatal if missing)
Expand Down Expand Up @@ -2043,7 +2065,7 @@ jobs:
$text = Get-Content -Raw -LiteralPath $found
if ($null -eq $text) { $text = "" }
if ($text.Length -eq 0) {
"### $title ($found empty)" | Out-File -Append $env:GITHUB_STEP_SUMMARY
"### $title ($found -- empty)" | Out-File -Append $env:GITHUB_STEP_SUMMARY
return
}
if ($text.Length -gt $max) { $text = $text.Substring(0,$max) + "`n... [truncated]" }
Expand Down Expand Up @@ -2686,7 +2708,7 @@ jobs:
$html = @"
<!doctype html>
<meta charset="utf-8">
<title>CI Diagnostics run ${{ github.run_id }}</title>
<title>CI Diagnostics -- run ${{ github.run_id }}</title>
<style>
body{font-family:ui-monospace,Consolas,monospace;white-space:pre-wrap;margin:24px}
h1,h2{font-family:ui-sans-serif,system-ui}
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/pr-automerge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
if (pr.mergeable === 'MERGEABLE') {
try {
await github.rest.pulls.merge({ owner, repo, pull_number: number, merge_method: 'squash' });
core.info(`#${number}: Merged directly (viewerCanEnable=false path) `);
core.info(`#${number}: Merged directly (viewerCanEnable=false path) [OK]`);
} catch (mergeErr) {
core.info(`#${number}: Direct merge failed: ${mergeErr.message || String(mergeErr)}`);
}
Expand All @@ -119,7 +119,7 @@ jobs:
await github.graphql(enable, { id: pr.id });
const { data: after } = await github.rest.pulls.get({ owner, repo, pull_number: number });
if (after.auto_merge) {
core.info(`#${number}: Auto-merge enabled (Squash) via PAT `);
core.info(`#${number}: Auto-merge enabled (Squash) via PAT [OK]`);
} else {
core.info(`#${number}: enable via PAT reported success, but REST auto_merge is null (will rely on diagnostics).`);
}
Expand All @@ -131,7 +131,7 @@ jobs:
if (pr.mergeable === 'MERGEABLE') {
try {
await github.rest.pulls.merge({ owner, repo, pull_number: number, merge_method: 'squash' });
core.info(`#${number}: Merged directly (PR was immediately mergeable) `);
core.info(`#${number}: Merged directly (PR was immediately mergeable) [OK]`);
} catch (mergeErr) {
core.info(`#${number}: Direct merge failed: ${mergeErr.message || String(mergeErr)}`);
}
Expand Down Expand Up @@ -172,7 +172,7 @@ jobs:
await github.graphql(enable, { id: prRest.node_id || prRest.id /* node_id expected */ });
const { data: after } = await github.rest.pulls.get({ owner, repo, pull_number: number });
if (after.auto_merge) {
core.info(`#${number}: Auto-merge enabled (Squash) via GITHUB_TOKEN `);
core.info(`#${number}: Auto-merge enabled (Squash) via GITHUB_TOKEN [OK]`);
} else {
core.info(`#${number}: enable via GITHUB_TOKEN reported success, but REST auto_merge is null (permissions likely).`);
}
Expand All @@ -184,7 +184,7 @@ jobs:
if (prRest.mergeable === true) {
try {
await github.rest.pulls.merge({ owner, repo, pull_number: number, merge_method: 'squash' });
core.info(`#${number}: Merged directly (PR was immediately mergeable) `);
core.info(`#${number}: Merged directly (PR was immediately mergeable) [OK]`);
} catch (mergeErr) {
core.info(`#${number}: Direct merge failed: ${mergeErr.message || String(mergeErr)}`);
}
Expand Down
21 changes: 21 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,27 @@ further.)*
currently-unused `conda_avail` step to right after `selfapps_envsmoke.ps1`, re-point the same
36 `if:` conditions at it), pending the owner's explicit go-ahead.

**Owner explicitly authorized proceeding ("if confident then implement or register open
question," same day) -- split into two staged PRs rather than one shot, since one shot is
exactly the pattern that produced both prior bugs.** Step 1 (this commit): moved the existing
`conda_avail` step from right after "Bootstrap environment" to right after "Self-test: real env
smoke (CI-only)" (`selfapps_envsmoke.ps1`) -- **deliberately left completely unwired, zero `if:`
conditions reference it yet.** A genuinely new wrinkle surfaced mid-implementation, worth
recording since it wasn't visible from the trace alone: in the ORIGINAL (buggy) design,
`selfapps_envsmoke.ps1` itself was one of the 9 "every non-corrupted lane" steps gated behind
`conda_avail` -- but envsmoke is now the PRODUCER of the signal this step reads, not a consumer,
so it must stay unconditional (`!cancelled() && env.HP_CACHE_CORRUPTED != '1'`, no `conda_avail`
clause) or the exact same circularity would return in a new spot. The other 8 steps in that
"every lane" category (empty-repo, single-entry, entry-selection, isolation, env-name, reqspec,
UX-hardening, system-Python-consent) are likewise NOT candidates for the gate going forward --
the real target is specifically the 27 steps already enumerated above as "silently skipped"
(22 `real/conda-full` + 5 `conda-full`-only), which all sit after envsmoke in file order.
Landing the corrected POSITION on its own first, with nothing depending on it, lets the very
next `conda-full` CI run prove (via its own step log) that `available` now correctly flips to
`'true'` once envsmoke's real install succeeds -- before any gating logic is re-added in a
follow-up commit. Watch that first run closely before proceeding to step 2 (wiring the 27
conditions).

## Cold Storage (promising ideas, deliberately shelved -- revisit only if a named trigger fires)

**Scope, and how this differs from Active Backlog and Known Findings**: an Active Backlog item is
Expand Down
13 changes: 12 additions & 1 deletion docs/agent-ndjson.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ self.corrupt.conda.detect,
self.corrupt.conda.heal.decline,
self.corrupt.conda.heal.accept,
self.corrupt.conda.override_exit,
self.corrupt.uv.detect
self.corrupt.uv.detect,
diag.conda.available
```

`self.corrupt.conda.override_exit` (CLAUDE.md Active Backlog item 12) covers the
Expand Down Expand Up @@ -528,6 +529,16 @@ self.interactive.stdin.roundtrip
recovery loop's own rebuilds -- a REPEATED module name would be rejected by
`~hidden_import_scan.py`'s own tried-list exclusion and stop the loop early via "no next hidden
import found", never reaching the iteration cap this test needs to exercise.
- `diag.conda.available` (inline `.github/workflows/batch-check.yml`, the "Check Miniconda
availability (diagnostic only -- not yet wired to any if: condition)" step -- see CLAUDE.md
Active Backlog item 7's `conda_avail` history) is always `pass: true` (non-gating; the step
itself never fails the job) and carries `details.available` (`true`/`false`) reflecting whether
Miniconda was found at the shared `%PUBLIC%\Documents\Miniconda3` path at that point in the job.
Added on PR #394 per a CodeRabbit finding: the step's own `Write-Host`/output had been observable
since PR #390 with no NDJSON row. Present in every non-`HP_CACHE_CORRUPTED` lane run regardless
of `matrix.mode`, since the step itself has no lane restriction (only its future `if:` wiring,
deferred pending owner sign-off per the same backlog item, will restrict its meaning to
`real`/`conda-full`).
- A row absent from the diag site means the test script either was not reached, threw
before the `Write-NdjsonRow` call, or the lane skipped that selfapps file.
- Rows gated by `pyFileCount` (e.g. `entry.single.direct`) will be absent whenever the
Expand Down
2 changes: 1 addition & 1 deletion promo/avc-icon-dark-base.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion promo/avc-icon-dark-contrast.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion promo/avc-icon-purplebg-whitecouch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions promo/avc_horizontal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions promo/avc_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading