diff --git a/CLAUDE.md b/CLAUDE.md index 0e36b1cc..fa6a0b56 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -516,14 +516,15 @@ See **AGENTS.md** section Iteration Contract for the full policy. Key points: Items deferred to future loops. This list is for genuine future work -- a decision already made, a fact confirmed with no action needed, or a recurring/periodic check belongs in -"Known Findings", `docs/agent-lessons-learned.md`, or "Periodic Maintenance Checks" below instead; -a promising idea deliberately shelved pending a specific, named trigger belongs in "Cold Storage" -below instead of here (see that section's own scope note for the distinction from this one). -Item numbers are informal labels for cross-referencing within a session or PR, not a -guaranteed-unique ID scheme -- pick anything that looks free in the list below when filing a new -item; do not cross-check it against `docs/agent-closed-backlog.md`'s history first, and do not -renumber an item if it later turns out to coincidentally repeat an older, already-closed item's -number. (Owner decision 2026-07-31, see Known Findings below: the earlier renumber-on-collision +`docs/agent-closed-backlog.md`'s "Known Findings" section, `docs/agent-lessons-learned.md`, or +"Periodic Maintenance Checks" below instead; a promising idea deliberately shelved pending a +specific, named trigger belongs in "Cold Storage" below instead of here (see that section's own +scope note for the distinction from this one). Item numbers are informal labels for +cross-referencing within a session or PR, not a guaranteed-unique ID scheme -- pick anything that +looks free in the list below when filing a new item; do not cross-check it against +`docs/agent-closed-backlog.md`'s history first, and do not renumber an item if it later turns out +to coincidentally repeat an older, already-closed item's number. (Owner decision 2026-07-31, see +`docs/agent-closed-backlog.md`'s Known Findings section: the earlier renumber-on-collision convention was more rigor than a plain-text backlog needs -- a real uniqueness guarantee belongs in an actual issue tracker, e.g. GitHub Issues, not a hand-maintained numbering scheme here.) Once an item is fully resolved it is removed from here entirely and archived (keeping its @@ -551,7 +552,7 @@ is not. row's mechanism explained at length in both `agent-interconnect.md` and `agent-ndjson.md` (canonical home: agent-ndjson.md). Zero information loss -- each fact still lives at its one canonical home, with a one-line pointer left everywhere else. - - **Loop 2 (open):** move CLAUDE.md's own "Known Findings" section to + - **Loop 2 (DONE, PR #430):** moved CLAUDE.md's own "Known Findings" section to `docs/agent-closed-backlog.md` -- it is explicitly "diagnosed, no action warranted," which is verbatim that file's own stated scope ("read on demand... when investigating something that feels like it was already done"), so it doesn't belong in the always-loaded file at all. @@ -709,9 +710,10 @@ every single PR), not correctness -- nothing about the lane itself is broken. computed once at pin-time and independently verified, never trusted from a third-party checksum file fetched over the same network path as the download itself). - **Next-pin probe**: this table's own quarterly refresh (checking python.org for a new minor) - already covers this on the "does a new version exist" axis. If REQ-AV's Tier B (dropped from the - backlog entirely -- see the Known Findings entry below for why and what restarts it; PRD at - `docs/prd-av-safe-build-path.md`) ever ships its own Python-3.12 pin for Nuitka/MinGW64 compatibility, + already covers this on the "does a new version exist" axis. If REQ-AV's Tier B (shelved in Cold + Storage, not dropped -- see `docs/agent-cold-storage.md`'s Tier B entry for why and what + restarts it; PRD at `docs/prd-av-safe-build-path.md`) ever ships its own Python-3.12 pin for + Nuitka/MinGW64 compatibility, add a matching probe here: periodically check whether Nuitka's MinGW64 backend has resumed Python 3.13+ support upstream, since that specific fact (not a general "try a newer version and see") is what the 3.12 pin depends on -- see that PRD's "Notes from Claude" section for why @@ -756,154 +758,11 @@ of a second or third pin actually needing it. ## Known Findings (diagnosed, no action warranted) -- **Backlog item numbering: renumber-on-collision convention dropped, 2026-07-31 owner decision.** - A prior pass found that Active Backlog items 9 and 11 (filed 2026-07-29) each collided with an - older, already-closed item of the same number, and -- following a convention this file used to - document -- renumbered them to 17 and 16 when archiving (see `docs/agent-closed-backlog.md`'s - Item 16/17 entries; left as-is, not worth unwinding already-completed, harmless work). That same - pass flagged the remaining active items (8, 10, 12, 13, 14, 15) as likely sharing the same - collision, filed as its own Active Backlog item to renumber them individually in a future pass. - **Owner call: this is unnecessary maintenance overhead for a plain-text backlog** -- there is no - practical way to keep hand-tracking collision-free numbers against a growing closed-history - archive without an extra bookkeeping system, and a real uniqueness guarantee belongs in an - actual issue tracker (e.g. GitHub Issues) if it's ever genuinely needed, not a markdown - convention here. Decision: item numbers are now informal, non-unique labels (see the Active - Backlog section's own updated intro text above); items 8, 10, 12, 13, 14, 15 keep their current - numbers permanently, coincidental collisions with closed-item numbers are not a defect, and the - item that tracked renumbering them is closed with no further action. - -- **Cascade consent gate design (timed prompt, decline-by-default) kept exactly as shipped, - 2026-07-26 owner decision -- closes the former cascade-consent question in - `docs/open-questions.md`.** Following the - cascade-vs-postexec fix (see Closed Backlog), a deeper investigation into the reliability of - the `HP_CASCADE_CANDIDATE` signal was requested and completed -- a full truth table over its - two constituent build-time static signals, with estimated odds the `.exe` still runs fine and - odds each next provider tier would actually help, now preserved in - `docs/agent-interconnect.md`'s "Cascade signal reliability" subsection (under "Post-execution - checkpoint") rather than in the open-questions file, per that file's own convention of folding - resolved questions into wherever they actually belong. Headline finding: the signal is real but - imperfect (an estimated 60-75% chance of a genuine problem when it fires, not a certainty), and - the uv->conda hop specifically has real, mechanism-level justification (a genuinely different - package index) that later hops (conda->embed->venv->system, all pip/PyPI-based once bootstrapped) - largely lack. - - **Considered, not adopted**: flipping the timed prompt's default from decline (N) to accept - (Y), specifically for the uv->conda hop, on the strength of that hop's own justification. - - **Decision: keep `:cascade_consent_gate` exactly as shipped** -- the timed `choice /T` prompt, - defaulting to decline (N) on timeout, unchanged for every hop including uv->conda. No code - change resulted from this investigation. - - Also considered and left out of the same pass, for a different reason (flagged as possibly - too risky to be wrong and too complex to be robust, and the analysis didn't fully resolve - that concern): telling the user their specific odds that the NEXT tier would help. Still not - implemented. - -- **The official `irm https://astral.sh/uv/install.ps1 | iex` installer script was researched as - a possible replacement for the current uv acquisition method -- rejected, current approach is - correct.** (Note: the exact official URL is `https://astral.sh/uv/install.ps1`, not the bare - `https://astral.sh` domain -- verified directly against astral.sh's own installation docs.) The - bootstrapper currently downloads uv's release zip directly from GitHub - (`HP_UV_URL`/`HP_UV_FALLBACK_URL`, run_setup.bat) and extracts `uv.exe` into a private - `~uv_bin\` directory that is prepended to `PATH` for the current process only (REQ-010 session - isolation). The official installer script does something architecturally different and worse - for this bootstrapper's needs: it installs uv to a persistent, shared, user-global location and - writes a PATH update to the user's shell profile/registry -- a footprint the installer script's - own documentation and general Windows tooling behavior both confirm requires a **fresh terminal - window** to take effect, since PATH updates never propagate into an already-running process. - That is fundamentally incompatible with `run_setup.bat`'s zero-terminal-restart promise (the - same class of restart/PATH-propagation hazard flagged independently in - `docs/prd-av-safe-build-path.md`'s Finding 6) -- the bootstrapper needs to use uv immediately, - within the same running batch process, with no user interaction. It also conflicts with two of - this repo's own stated Bootstrap Architecture Principles in this file (above): "Never depend on - console scripts during bootstrap" and preferring a private, disposable footprint over a shared, - persistent one -- the same reasoning that separately ruled out winget/Microsoft Store Python as - a REQ-009 tier. Decision: keep the current direct-zip-to-private-directory approach; the - installer script is the right choice for a normal interactive user setting up their own - machine, not for a script that needs the tool usable in the same process that downloaded it. - -- **Embed zip download has no genuine second-host fallback available, unlike Miniconda/uv/get-pip - -- researched, no action planned.** A background code-review pass flagged that the embed tier's - download (`:try_embed_fallback`, run_setup.bat) retries the *same* `HP_EMBED_URL` - (`www.python.org/ftp/python/...`) on failure, unlike Miniconda (has a `repo.continuum.io` legacy - alias), uv (has a pinned-release GitHub URL distinct from its "latest" CDN redirect), and get-pip - (has the get-pip project's own GitHub source as a second host). Researched whether an equivalent - second host exists for python.org's embeddable zip distribution: it does not, in the same sense. - `www.python.org/ftp` is itself the canonical, Fastly-CDN-backed distribution point for CPython - releases -- there is no alternate *official* domain serving the identical embeddable-zip artifact. - python.org does list community mirrors, but none are guaranteed to carry the embeddable-zip - variant specifically, or to match this repo's pinned SHA256 the way the primary source does by - construction (the checksum was computed directly from a `python.org/ftp` download at pin time) -- - pointing at one would be a real trust/availability decision, not a mechanical copy of the - Miniconda/uv/get-pip pattern. Decision: no forced fallback host. The existing 2-attempt - same-URL retry (curl, then PowerShell `Invoke-WebRequest`) already covers the common transient - failure case; a genuine second-host fallback remains possible future work if a specific mirror is - ever vetted, but is not a quick win and is not planned. **One specific candidate WAS identified - and considered, then rejected**: the CPython core team publishes an embeddable-equivalent build - to NuGet (`nuget.org/packages/python`) as part of their official release process -- a real, - independently-hosted, officially-maintained artifact on a different CDN (Azure-backed vs. - Fastly), reachable without the NuGet client via `nuget.org/api/v2/package/python/`. - Rejected because it is not the same artifact the pinned `EMBED_PYTHON_TABLE` checksums were - computed against -- using it would mean maintaining a second SHA256 column per pinned version - going forward, doubling the table's maintenance burden for a download that's already covered by - the existing 2-attempt retry against a CDN that's rarely actually down. Revisit only if the - same-host retry proves insufficient in practice. - -- **winget / Microsoft Store Python evaluated as a possible additional REQ-009 tier -- rejected, - no action planned.** Considered whether `winget install Python.Python.3` (or the Microsoft Store - Python package) could serve as another fresh-acquisition fallback alongside or instead of the - embedded-Python tier. Researched winget's actual install behavior: without an explicit - `--scope machine` flag (which needs elevation), it installs **per-user** to - `%LOCALAPPDATA%\Programs\Python\Python3XX` -- but "per-user" is not the same axis as "isolated" - in the sense the embed tier cares about. Unlike embed's private, checksummed, disposable - `~embed_python\` directory (never registered anywhere, verified before use, gone if the app - stops using it), a winget/Store install is **shared and persistent**: it registers itself on - PATH, in Add/Remove Programs, and in the App Execution Alias registry, is discoverable by other - applications and future bootstrap runs of *other* projects, and its integrity is delegated - entirely to winget's own signature verification rather than this repo's own embedded SHA256. - Architecturally this makes it closer to the **system** tier (shared, uncontrolled, arguably - needing the same REQ-014-style consent) than to the **embed** tier (private, disposable, - pre-verified) -- adding it would mostly duplicate embed's job (fresh acquisition) with weaker - isolation, for the same underlying failure causes embed already fails for (no network, or -- for - winget itself -- winget/App Installer not being present on an older Windows 10 build, which is - its own new dependency this bootstrapper doesn't otherwise have). Decision: not worth adding as - a 6th tier. - -- **User-code exit-code semantics are already correctly isolated from bootstrapper status -- - verified, no action needed.** Traced the full flow: `HP_SMOKE_RC` is captured directly from - `%ERRORLEVEL%` immediately after launching the user's program at every verification call site - (`:run_exe_smokerun`'s EXE smoke, `:verify_no_exe_interpreter`'s interpreter run, - `:run_failfast_probe`'s interactive probe), via goto-based dispatch (not nested in a - parenthesized if/else) with no bootstrapper logic interleaved between launch and capture -- - confirms it is purely the user program's own exit code. Separately confirmed the - bootstrapper's own reported status is entirely decoupled: the terminating `exit /b 0` at the - end of the `:success` label (the actual `run_setup.bat` process exit code on a real - double-click) and every `call :write_status ok 0 ...` site pass a hardcoded literal `0`, - never `%HP_SMOKE_RC%` -- so a crashing/non-zero-exiting user program is never reported as a - bootstrapper failure. `~bootstrap.status.json`'s `exitCode` field means "did the - bootstrapper's own env/build lifecycle succeed," not "what did the user's program return"; - the true user-program outcome is surfaced separately via the console - `[STATUS] Run Status: SUCCESS/FAILED (Exit Code: N)` line. Also confirmed such a case does - not get misrouted into repair logic: the `--hidden-import` auto-recovery loop only engages - for a narrow signature (`ModuleNotFoundError` of a module that IS installed in the build - interpreter -- see "--hidden-import auto-recovery must stay STRICT" in - `docs/agent-lessons-learned.md`); any other user-program failure (a logic bug, an unrelated - unhandled exception, etc.) takes no recovery action and is left exactly as observed, correctly - not conflated with a packaging/bootstrapper problem. No code change needed; existing behavior - already satisfies the intent. - -- **NI-VISA real install fails fast in CI (`installer_rc=-125083`) -- environmental, NOT a repo/test/CI-code - bug.** Diagnosed via the REQ-008 `[VISA]` diagnostic logging (download method / file size / PE check / - installer exit code, surfaced in the `pyvisa.nivisa.reason` NDJSON details). On the conda-full lane the - installer downloads cleanly via curl (~6.77 MB, `PE_OK` -- a genuine NI-VISA 21.5 online bootstrapper), - then runs and exits `-125083` in ~10s. Because the install uses `start /wait`, the post-check budget never - kills it; the failure is the online bootstrapper being unable to complete an unattended install on the - runner (network policy to NI's package feed and/or no interactive/elevation path). Consequences: - `[VISA] install_success` is **unreachable in CI by design**; the validated behavior is - detect -> attempt -> log rc -> continue gracefully; **no dedicated real-install lane is warranted** (there - is no slow-but-succeeding install to wait out). `HP_NIVISA_WAIT_SECS` remains a useful knob only for the - narrow detached-child registry-propagation case. - - **NOT YET CONFIRMED on a real machine.** This conclusion rests solely on CI evidence. It still needs a - real user run (normal internet, interactive/admin session) to confirm the same valid installer succeeds - off-CI (expected ~30-45 min per the maintainer's prior experience). Until then, treat the - "environmental" classification as strongly-supported-but-provisional. +Moved to `docs/agent-closed-backlog.md` (2026-08-09, Active Backlog Item 34 Loop 2). Real +investigations that concluded "no action needed" or "considered and rejected, with reasoning" -- +this section's own scope is verbatim that file's stated purpose (read on demand, not every +session), so it doesn't belong in the always-loaded file. Check that file's "Known Findings" +section before re-investigating something that might already have a documented, closed answer. ## Closed Backlog diff --git a/docs/agent-closed-backlog.md b/docs/agent-closed-backlog.md index e0178ea0..a2b35dd1 100644 --- a/docs/agent-closed-backlog.md +++ b/docs/agent-closed-backlog.md @@ -20,11 +20,15 @@ likely be reorganized again as it grows. Treat a Part/Scenario citation here as look," not a precise current coordinate; this file is an append-only historical record, so its own entries are not retroactively renumbered to track that doc's current structure. -**Two sections below.** "Closed Active Backlog Items" holds items that were promoted out of +**Three sections below.** "Closed Active Backlog Items" holds items that were promoted out of `CLAUDE.md`'s own "Active Backlog" section once fully resolved (each keeps its original item -number for cross-reference stability -- other docs cite these by number). "Closed Backlog" is -`CLAUDE.md`'s own pre-existing changelog-style record of completed feature/fix work, moved here -verbatim. +number for cross-reference stability -- other docs cite these by number). "Known Findings" +(moved here verbatim from `CLAUDE.md`, 2026-08-09, Active Backlog Item 34 Loop 2) holds +diagnosed-no-action-warranted investigations -- a question was raised, researched, and answered +with "no code change needed" or "considered and rejected, with reasoning" -- distinct from a +Closed Active Backlog item (resolved with a real change) or an open Active Backlog item (still +pending). "Closed Backlog" is `CLAUDE.md`'s own pre-existing changelog-style record of completed +feature/fix work, moved here verbatim. --- @@ -1892,6 +1896,157 @@ this belongs to). genuinely differ in actionability (`missing_output` suggests an AV/indexer conflict a user could investigate; `build_error`/`test_forced_fail` do not) and the token costs nothing to add. +## Known Findings (diagnosed, no action warranted) + +- **Backlog item numbering: renumber-on-collision convention dropped, 2026-07-31 owner decision.** + A prior pass found that Active Backlog items 9 and 11 (filed 2026-07-29) each collided with an + older, already-closed item of the same number, and -- following a convention this file used to + document -- renumbered them to 17 and 16 when archiving (see this file's own Item 16/17 entries + above; left as-is, not worth unwinding already-completed, harmless work). That same + pass flagged the remaining active items (8, 10, 12, 13, 14, 15) as likely sharing the same + collision, filed as its own Active Backlog item to renumber them individually in a future pass. + **Owner call: this is unnecessary maintenance overhead for a plain-text backlog** -- there is no + practical way to keep hand-tracking collision-free numbers against a growing closed-history + archive without an extra bookkeeping system, and a real uniqueness guarantee belongs in an + actual issue tracker (e.g. GitHub Issues) if it's ever genuinely needed, not a markdown + convention here. Decision: item numbers are now informal, non-unique labels (see `CLAUDE.md`'s + Active Backlog section's own intro text); items 8, 10, 12, 13, 14, 15 keep their current + numbers permanently, coincidental collisions with closed-item numbers are not a defect, and the + item that tracked renumbering them is closed with no further action. + +- **Cascade consent gate design (timed prompt, decline-by-default) kept exactly as shipped, + 2026-07-26 owner decision -- closes the former cascade-consent question in + `docs/open-questions.md`.** Following the + cascade-vs-postexec fix (see Closed Backlog below), a deeper investigation into the reliability + of the `HP_CASCADE_CANDIDATE` signal was requested and completed -- a full truth table over its + two constituent build-time static signals, with estimated odds the `.exe` still runs fine and + odds each next provider tier would actually help, now preserved in + `docs/agent-interconnect.md`'s "Cascade signal reliability" subsection (under "Post-execution + checkpoint") rather than in the open-questions file, per that file's own convention of folding + resolved questions into wherever they actually belong. Headline finding: the signal is real but + imperfect (an estimated 60-75% chance of a genuine problem when it fires, not a certainty), and + the uv->conda hop specifically has real, mechanism-level justification (a genuinely different + package index) that later hops (conda->embed->venv->system, all pip/PyPI-based once bootstrapped) + largely lack. + - **Considered, not adopted**: flipping the timed prompt's default from decline (N) to accept + (Y), specifically for the uv->conda hop, on the strength of that hop's own justification. + - **Decision: keep `:cascade_consent_gate` exactly as shipped** -- the timed `choice /T` prompt, + defaulting to decline (N) on timeout, unchanged for every hop including uv->conda. No code + change resulted from this investigation. + - Also considered and left out of the same pass, for a different reason (flagged as possibly + too risky to be wrong and too complex to be robust, and the analysis didn't fully resolve + that concern): telling the user their specific odds that the NEXT tier would help. Still not + implemented. + +- **The official `irm https://astral.sh/uv/install.ps1 | iex` installer script was researched as + a possible replacement for the current uv acquisition method -- rejected, current approach is + correct.** (Note: the exact official URL is `https://astral.sh/uv/install.ps1`, not the bare + `https://astral.sh` domain -- verified directly against astral.sh's own installation docs.) The + bootstrapper currently downloads uv's release zip directly from GitHub + (`HP_UV_URL`/`HP_UV_FALLBACK_URL`, run_setup.bat) and extracts `uv.exe` into a private + `~uv_bin\` directory that is prepended to `PATH` for the current process only (REQ-010 session + isolation). The official installer script does something architecturally different and worse + for this bootstrapper's needs: it installs uv to a persistent, shared, user-global location and + writes a PATH update to the user's shell profile/registry -- a footprint the installer script's + own documentation and general Windows tooling behavior both confirm requires a **fresh terminal + window** to take effect, since PATH updates never propagate into an already-running process. + That is fundamentally incompatible with `run_setup.bat`'s zero-terminal-restart promise (the + same class of restart/PATH-propagation hazard flagged independently in + `docs/prd-av-safe-build-path.md`'s Finding 6) -- the bootstrapper needs to use uv immediately, + within the same running batch process, with no user interaction. It also conflicts with two of + `CLAUDE.md`'s own stated Bootstrap Architecture Principles: "Never depend on + console scripts during bootstrap" and preferring a private, disposable footprint over a shared, + persistent one -- the same reasoning that separately ruled out winget/Microsoft Store Python as + a REQ-009 tier. Decision: keep the current direct-zip-to-private-directory approach; the + installer script is the right choice for a normal interactive user setting up their own + machine, not for a script that needs the tool usable in the same process that downloaded it. + +- **Embed zip download has no genuine second-host fallback available, unlike Miniconda/uv/get-pip + -- researched, no action planned.** A background code-review pass flagged that the embed tier's + download (`:try_embed_fallback`, run_setup.bat) retries the *same* `HP_EMBED_URL` + (`www.python.org/ftp/python/...`) on failure, unlike Miniconda (has a `repo.continuum.io` legacy + alias), uv (has a pinned-release GitHub URL distinct from its "latest" CDN redirect), and get-pip + (has the get-pip project's own GitHub source as a second host). Researched whether an equivalent + second host exists for python.org's embeddable zip distribution: it does not, in the same sense. + `www.python.org/ftp` is itself the canonical, Fastly-CDN-backed distribution point for CPython + releases -- there is no alternate *official* domain serving the identical embeddable-zip artifact. + python.org does list community mirrors, but none are guaranteed to carry the embeddable-zip + variant specifically, or to match this repo's pinned SHA256 the way the primary source does by + construction (the checksum was computed directly from a `python.org/ftp` download at pin time) -- + pointing at one would be a real trust/availability decision, not a mechanical copy of the + Miniconda/uv/get-pip pattern. Decision: no forced fallback host. The existing 2-attempt + same-URL retry (curl, then PowerShell `Invoke-WebRequest`) already covers the common transient + failure case; a genuine second-host fallback remains possible future work if a specific mirror is + ever vetted, but is not a quick win and is not planned. **One specific candidate WAS identified + and considered, then rejected**: the CPython core team publishes an embeddable-equivalent build + to NuGet (`nuget.org/packages/python`) as part of their official release process -- a real, + independently-hosted, officially-maintained artifact on a different CDN (Azure-backed vs. + Fastly), reachable without the NuGet client via `nuget.org/api/v2/package/python/`. + Rejected because it is not the same artifact the pinned `EMBED_PYTHON_TABLE` checksums were + computed against -- using it would mean maintaining a second SHA256 column per pinned version + going forward, doubling the table's maintenance burden for a download that's already covered by + the existing 2-attempt retry against a CDN that's rarely actually down. Revisit only if the + same-host retry proves insufficient in practice. + +- **winget / Microsoft Store Python evaluated as a possible additional REQ-009 tier -- rejected, + no action planned.** Considered whether `winget install Python.Python.3` (or the Microsoft Store + Python package) could serve as another fresh-acquisition fallback alongside or instead of the + embedded-Python tier. Researched winget's actual install behavior: without an explicit + `--scope machine` flag (which needs elevation), it installs **per-user** to + `%LOCALAPPDATA%\Programs\Python\Python3XX` -- but "per-user" is not the same axis as "isolated" + in the sense the embed tier cares about. Unlike embed's private, checksummed, disposable + `~embed_python\` directory (never registered anywhere, verified before use, gone if the app + stops using it), a winget/Store install is **shared and persistent**: it registers itself on + PATH, in Add/Remove Programs, and in the App Execution Alias registry, is discoverable by other + applications and future bootstrap runs of *other* projects, and its integrity is delegated + entirely to winget's own signature verification rather than this repo's own embedded SHA256. + Architecturally this makes it closer to the **system** tier (shared, uncontrolled, arguably + needing the same REQ-014-style consent) than to the **embed** tier (private, disposable, + pre-verified) -- adding it would mostly duplicate embed's job (fresh acquisition) with weaker + isolation, for the same underlying failure causes embed already fails for (no network, or -- for + winget itself -- winget/App Installer not being present on an older Windows 10 build, which is + its own new dependency this bootstrapper doesn't otherwise have). Decision: not worth adding as + a 6th tier. + +- **User-code exit-code semantics are already correctly isolated from bootstrapper status -- + verified, no action needed.** Traced the full flow: `HP_SMOKE_RC` is captured directly from + `%ERRORLEVEL%` immediately after launching the user's program at every verification call site + (`:run_exe_smokerun`'s EXE smoke, `:verify_no_exe_interpreter`'s interpreter run, + `:run_failfast_probe`'s interactive probe), via goto-based dispatch (not nested in a + parenthesized if/else) with no bootstrapper logic interleaved between launch and capture -- + confirms it is purely the user program's own exit code. Separately confirmed the + bootstrapper's own reported status is entirely decoupled: the terminating `exit /b 0` at the + end of the `:success` label (the actual `run_setup.bat` process exit code on a real + double-click) and every `call :write_status ok 0 ...` site pass a hardcoded literal `0`, + never `%HP_SMOKE_RC%` -- so a crashing/non-zero-exiting user program is never reported as a + bootstrapper failure. `~bootstrap.status.json`'s `exitCode` field means "did the + bootstrapper's own env/build lifecycle succeed," not "what did the user's program return"; + the true user-program outcome is surfaced separately via the console + `[STATUS] Run Status: SUCCESS/FAILED (Exit Code: N)` line. Also confirmed such a case does + not get misrouted into repair logic: the `--hidden-import` auto-recovery loop only engages + for a narrow signature (`ModuleNotFoundError` of a module that IS installed in the build + interpreter -- see "--hidden-import auto-recovery must stay STRICT" in + `docs/agent-lessons-learned.md`); any other user-program failure (a logic bug, an unrelated + unhandled exception, etc.) takes no recovery action and is left exactly as observed, correctly + not conflated with a packaging/bootstrapper problem. No code change needed; existing behavior + already satisfies the intent. + +- **NI-VISA real install fails fast in CI (`installer_rc=-125083`) -- environmental, NOT a repo/test/CI-code + bug.** Diagnosed via the REQ-008 `[VISA]` diagnostic logging (download method / file size / PE check / + installer exit code, surfaced in the `pyvisa.nivisa.reason` NDJSON details). On the conda-full lane the + installer downloads cleanly via curl (~6.77 MB, `PE_OK` -- a genuine NI-VISA 21.5 online bootstrapper), + then runs and exits `-125083` in ~10s. Because the install uses `start /wait`, the post-check budget never + kills it; the failure is the online bootstrapper being unable to complete an unattended install on the + runner (network policy to NI's package feed and/or no interactive/elevation path). Consequences: + `[VISA] install_success` is **unreachable in CI by design**; the validated behavior is + detect -> attempt -> log rc -> continue gracefully; **no dedicated real-install lane is warranted** (there + is no slow-but-succeeding install to wait out). `HP_NIVISA_WAIT_SECS` remains a useful knob only for the + narrow detached-child registry-propagation case. + - **NOT YET CONFIRMED on a real machine.** This conclusion rests solely on CI evidence. It still needs a + real user run (normal internet, interactive/admin session) to confirm the same valid installer succeeds + off-CI (expected ~30-45 min per the maintainer's prior experience). Until then, treat the + "environmental" classification as strongly-supported-but-provisional. + ## Closed Backlog - **Cascade-vs-postexec fix (Active Backlog item 9), 2026-07-25, owner-directed follow-up to a diff --git a/docs/agent-interconnect.md b/docs/agent-interconnect.md index af75a76b..4a25440e 100644 --- a/docs/agent-interconnect.md +++ b/docs/agent-interconnect.md @@ -1850,7 +1850,8 @@ timed.ps1` (conda-full lane) proves the timed-choice mechanism and the dirty-fla Investigated in response to a maintainer question about how confident this signal actually is, and whether the cascade consent gate's design (timed prompt, defaults to decline) should change as a -result. **Outcome: kept exactly as shipped -- see CLAUDE.md's Known Findings entry.** This +result. **Outcome: kept exactly as shipped -- see `docs/agent-closed-backlog.md`'s Known Findings +entry.** This subsection preserves the supporting mechanism-level analysis for anyone touching the signal again. `HP_CASCADE_CANDIDATE` requires BOTH of two build-time, static signals (`:warnfix_cascade_detect`): @@ -1898,5 +1899,5 @@ This supports, with a real mechanism behind it rather than just intuition, the i specifically to conda has real, justified value while later hops add comparatively little. The maintainer considered flipping the timed prompt's default from decline (N) to accept (Y) specifically for the uv->conda hop on this basis, but decided to keep `:cascade_consent_gate` -exactly as shipped (see CLAUDE.md's Known Findings entry for the full reasoning) -- no code -change resulted from this investigation. +exactly as shipped (see `docs/agent-closed-backlog.md`'s Known Findings entry for the full +reasoning) -- no code change resulted from this investigation. diff --git a/docs/plan-pvw-quickstart.md b/docs/plan-pvw-quickstart.md index e650c5aa..db9797f1 100644 --- a/docs/plan-pvw-quickstart.md +++ b/docs/plan-pvw-quickstart.md @@ -187,8 +187,9 @@ matching what's now shipped as README commands: - **Default (run, and additively remember what it needed):** install uv via the official installer (`irm https://astral.sh/uv/install.ps1 | iex`, already this repo's own documented recommendation - for an *interactive terminal* context -- see `CLAUDE.md`'s "Known Findings" entry explaining why - that same installer is deliberately **not** used inside `run_setup.bat` itself; a live terminal + for an *interactive terminal* context -- see `docs/agent-closed-backlog.md`'s "Known Findings" + entry explaining why that same installer is deliberately **not** used inside `run_setup.bat` + itself; a live terminal session has none of the PATH-propagation/restart problems a background batch process does, so there is no conflict between the two decisions, just two different execution contexts), read the target file with the ISO-8859-1 round-trip technique (`agent-lessons-learned.md`) so a crash or diff --git a/docs/prd-av-safe-build-path.md b/docs/prd-av-safe-build-path.md index 70a86543..f277c74a 100644 --- a/docs/prd-av-safe-build-path.md +++ b/docs/prd-av-safe-build-path.md @@ -231,13 +231,13 @@ This section was added by a Claude Code session with direct access to the live ` ### Overall assessment of the PRD -This is an unusually well-constructed PRD for a preemptive (not-yet-observed) risk: it cites primary sources (Nuitka's own docs and open issues, not secondhand summaries), it correctly self-corrected two real design mistakes across drafts (the v2 bare-3.12-interpreter mistake in Finding 1, and the always-reprovision cost in the earlier Tier A/B split), and it explicitly documents *why* it disagrees with a third-party Green/GO recommendation rather than either blindly adopting or silently ignoring it -- that's the right way to handle conflicting outside input, and this repo's own conventions (see `CLAUDE.md`'s "Known Findings" pattern of recording rejected alternatives with reasoning) already value exactly that kind of documented disagreement. The Yellow confidence rating is justified and should not be waved through to Green without the loop-avoidance tests (requirement 1) actually existing and passing against a real double-failure simulation. +This is an unusually well-constructed PRD for a preemptive (not-yet-observed) risk: it cites primary sources (Nuitka's own docs and open issues, not secondhand summaries), it correctly self-corrected two real design mistakes across drafts (the v2 bare-3.12-interpreter mistake in Finding 1, and the always-reprovision cost in the earlier Tier A/B split), and it explicitly documents *why* it disagrees with a third-party Green/GO recommendation rather than either blindly adopting or silently ignoring it -- that's the right way to handle conflicting outside input, and this repo's own conventions (see `docs/agent-closed-backlog.md`'s "Known Findings" pattern of recording rejected alternatives with reasoning) already value exactly that kind of documented disagreement. The Yellow confidence rating is justified and should not be waved through to Green without the loop-avoidance tests (requirement 1) actually existing and passing against a real double-failure simulation. One structural observation, not a defect: this PRD is large relative to how this repo actually ships work. `CLAUDE.md`'s Iteration Contract calls for "exactly ONE missing feature slice per loop," and even "Phase 1 (P0 only)" here bundles seven requirements spanning a new build backend, a two-tier reprovisioning decision, loop-avoidance state, environment-cleanliness guarantees, and a connectivity check. That's not a criticism of the PRD's scoping -- P0 genuinely can't be split much smaller without becoming incoherent -- it's a note for whoever picks this up: budget it as several loops, not one, and expect the "smallest viable change" framing in Timeline Considerations to mean *smallest viable **phase***, not a single sitting. ### Priority recommendation: way later, not now or soon -The Problem Statement is honest that "this risk has not yet caused a real reported failure" -- this is preemptive hardening against a well-documented *industry* problem (the Related Work section's citations are real and relevant), not a fix for anything this repo's own users have hit. Weighed against the size of Phase 1 alone (a second build backend, a two-tier fallback decision, new loop-avoidance state, new environment-cleanliness guarantees) and this repo's own stated discipline about not building ahead of a concrete, observed need (see the recently-rejected winget-as-a-tier and NuGet-as-a-fallback-host ideas in `CLAUDE.md`'s Known Findings -- both rejected specifically for being solutions to gaps that weren't actually biting anyone yet), my recommendation is: **keep this as a ready-to-execute, well-specified backlog item; do not schedule it now or soon.** Revisit when either (a) a real AV-quarantine report actually comes in from a user, or (b) there's a slow period with bandwidth for a genuine multi-loop initiative and nothing higher-value competing for it. This matches the PRD's own "no hard deadline... preemptive risk, not an active incident" framing -- I'm not disagreeing with the document, just making the "way later" framing explicit since the owner asked for a priority call. +The Problem Statement is honest that "this risk has not yet caused a real reported failure" -- this is preemptive hardening against a well-documented *industry* problem (the Related Work section's citations are real and relevant), not a fix for anything this repo's own users have hit. Weighed against the size of Phase 1 alone (a second build backend, a two-tier fallback decision, new loop-avoidance state, new environment-cleanliness guarantees) and this repo's own stated discipline about not building ahead of a concrete, observed need (see the recently-rejected winget-as-a-tier and NuGet-as-a-fallback-host ideas in `docs/agent-closed-backlog.md`'s Known Findings -- both rejected specifically for being solutions to gaps that weren't actually biting anyone yet), my recommendation is: **keep this as a ready-to-execute, well-specified backlog item; do not schedule it now or soon.** Revisit when either (a) a real AV-quarantine report actually comes in from a user, or (b) there's a slow period with bandwidth for a genuine multi-loop initiative and nothing higher-value competing for it. This matches the PRD's own "no hard deadline... preemptive risk, not an active incident" framing -- I'm not disagreeing with the document, just making the "way later" framing explicit since the owner asked for a priority call. ### On generalizing the Python-version-pin pattern beyond Tier B (owner's explicit request) diff --git a/tests/selfapps_ux_hardening.ps1 b/tests/selfapps_ux_hardening.ps1 index 26bd001d..feb08a54 100644 --- a/tests/selfapps_ux_hardening.ps1 +++ b/tests/selfapps_ux_hardening.ps1 @@ -895,8 +895,8 @@ if ($env:HP_FORCE_CONDA_ONLY -eq '1') { } catch { } } # derived requirement: run_setup.bat's own :die uses "exit /b" (a subroutine return, not a - # process exit) -- per CLAUDE.md's "Known Findings", the batch process can still exit 0 even - # after a logical failure, so ~bootstrap.status.json's state (not the raw process exit code) + # process exit) -- per agent-lessons-learned.md's ":die" entry, the batch process can still + # exit 0 even after a logical failure, so ~bootstrap.status.json's state (not the raw exit code) # is this codebase's own documented source of truth for "did it actually fail". processExit is # captured in details for diagnostics only, not asserted. $embedDeclineDied = ($embedDeclineState -eq 'error')