Skip to content

fix(#184): env, not a prefix assignment, for a readonly var into python3 - #188

Merged
aradanmn merged 1 commit into
mainfrom
fix/184-readonly-icon-url
Aug 1, 2026
Merged

aradanmn merged 1 commit into
mainfrom
fix/184-readonly-icon-url

Conversation

@aradanmn

@aradanmn aradanmn commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Closes #184.

Problem

Found live on two hardware runs during #122 validation:

```
system_integration.sh: line 268: MCSS_STEAMGRIDDB_ICON_URL: readonly variable
```

Fail-open, not fatal — the child still ran (a failed prefix assignment prints
its error and the command executes anyway under bash; this is not
set -e-fatal), but the value never reached it. `add-to-steam.py` fell back
to its own hardcoded default URL, which happens to match today's value, so
nothing visibly broke. If the two ever drift, they'd do so silently.

Root cause

`MCSS_STEAMGRIDDB_ICON_URL` is `readonly` in this shell (line 69,
deliberately — #91, "the ONE encoding of the icon URL"). A bash prefix
assignment (`VAR=val cmd`) looks child-scoped, but bash still touches the
parent's own variable-table entry for that name before handing the
environment to the child, and refuses when it's already readonly. `env`
spawns a genuinely separate process and never touches the parent binding at
all.

Confirmed against a real subprocess (not a builtin, which would misleadingly
appear to work via normal shell variable scoping rather than a real
environment handoff):

```
$ bash -c 'readonly X="a"; X="b" bash -c "echo child saw: $X"'
bash: line 1: X: readonly variable
child saw: # empty — not even "a"
$ bash -c 'readonly X="a"; env X="b" bash -c "echo child saw: $X"'
child saw: b
```

Tests

`tests/test_installer.sh`: 12→14.

  • T7.14 pins the general bash mechanism (env delivers past a readonly
    var; a prefix assignment silently does not) using a real subprocess.
  • T7.15 is structural — the real call site uses `env`. Exercising the
    whole Steam-integration function needs a live userdata tree, so this is
    the practical check that stays in sync with the code.

Mutation-tested: reverting to the buggy prefix-assignment form turns
T7.15 red (T7.14 is deliberately independent of the real file — it proves
the general mechanism, not this specific call site).

No CI baseline change — `test_installer.sh` stays excluded from the
pass-count gate (pre-existing network/branch-mismatch quirk, unrelated).

Not done

Not yet re-validated on the Deck (the original symptom was found and worked
around live during #122; this is the permanent fix). Will batch into the
same Deck sitting as #185/#186.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Dru6wVc2ZcjiTpa6p7yJDh

Found live on two hardware runs during #122 validation:

    system_integration.sh: line 268: MCSS_STEAMGRIDDB_ICON_URL: readonly variable

Fail-open, not fatal: the child still ran (this is not `set -e`-fatal — a
failed prefix assignment prints its error and the command executes anyway),
but the value never reached it. add-to-steam.py fell back to its own
hardcoded default URL, which happens to match today, so nothing visibly
broke. If the two ever drift, they'd do so silently.

Root cause: `MCSS_STEAMGRIDDB_ICON_URL` is `readonly` in this shell (line 69,
deliberately — #91, "the ONE encoding of the icon URL"). A bash prefix
assignment (`VAR=val cmd`) LOOKS child-scoped, but bash still touches the
PARENT's own variable-table entry for that name before handing the
environment to the child — and refuses when it's already readonly. `env`
spawns a genuinely separate process and never touches our binding at all.

Confirmed against a real python3 child (not just a builtin, which would
misleadingly appear to work via normal shell scoping rather than a real
environment handoff):

    $ bash -c 'readonly X="a"; X="b" bash -c "echo child saw: \$X"'
    bash: line 1: X: readonly variable
    child saw:                                    # empty — not even "a"
    $ bash -c 'readonly X="a"; env X="b" bash -c "echo child saw: \$X"'
    child saw: b

tests/test_installer.sh: +2 (12→14). T7.14 pins the general bash mechanism
(env delivers past a readonly var; a prefix assignment silently does not) —
this is what add-to-steam.py's OWN test would need if this ever recurs
elsewhere. T7.15 is structural: the real call site uses `env`, since
exercising the whole Steam-integration function needs a live userdata tree.

Mutation-tested: reverting to the buggy prefix-assignment form turns T7.15
red (T7.14 is deliberately mutation-independent of the real file — it proves
the general mechanism works, T7.15 is what pins the real site to using it).

No CI baseline change: test_installer.sh is excluded from the pass-count
gate (network/branch-mismatch quirk, unrelated to this fix) but still runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dru6wVc2ZcjiTpa6p7yJDh
@aradanmn
aradanmn force-pushed the fix/184-readonly-icon-url branch from 6a6d9fa to 49879fe Compare August 1, 2026 13:18
@aradanmn
aradanmn merged commit 5d78d25 into main Aug 1, 2026
4 checks passed
@aradanmn
aradanmn deleted the fix/184-readonly-icon-url branch August 1, 2026 13:19
aradanmn added a commit that referenced this pull request Aug 1, 2026
…#190)

Archives the morning's PLAN.md (docs/PLAN-20260801.md, per its own
versioning rule) and updates the canonical version:

- #122 (workdir consolidation + uninstaller --purge) SHIPPED, both
  hardware-validated on a real destructive purge + reinstall cycle.
- That validation found #184/#185/#186 — a readonly-var env-passing bug, a
  fake --yes flag plus two prompts that died silently on EOF, and an evsieve
  build failure caused by this Deck's kernel rejecting native-overlay
  ID-mapped mounts. All three fixed, CI-green, PRs #187/#188/#189 open,
  awaiting one batched Deck sitting to validate before merge.
- v1.2.4 milestone/estimate updated to reflect the remaining scope (#126,
  #36, plus merging+validating the three new fixes).
- Deck state refreshed: two full purge/reinstall cycles today, MC back on
  26.1.2 (matches the home-server pin, resolving the earlier 26.2 drift),
  current backup locations noted.
- New risk R11: a test-stub mutation-testing gap (a loose substring match
  let a typo'd value pass) — worth a second look wherever a stub does a
  substring case-match on a path/flag value.


Claude-Session: https://claude.ai/code/session_01Dru6wVc2ZcjiTpa6p7yJDh

Co-authored-by: Scott <scott@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
aradanmn added a commit that referenced this pull request Aug 1, 2026
…#191)

- v1.2.4 status: #187/#188/#189 merged AND hardware-validated tonight — a
  real `./install-minecraft-splitscreen.sh --yes < /dev/null` run completed
  end to end (no readonly-var error, no silent EOF death, evsieve built via
  the fuse-overlayfs fallback, confirmed live-running not a lucky native
  pass).
- #126a decided: CI cross-build, not build-on-Deck-and-upload. Full reasoning
  posted to the issue — short version: _evsieve_host_verify has passed on
  every build since PR1, which is direct proof stock SteamOS already ships
  libevdev.so.2, so the only real ABI risk is glibc, and SteamOS's (2.41) is
  newer than even ubuntu-24.04's (2.39). Static-linking libevdev, floated in
  the issue, isn't needed. release.yml already builds on tags; this is one
  more job in it, costing zero recurring Deck time versus a manual build
  that would need repeating on every evsieve pin/patch change.
- Deck state refreshed: fully validated working install, evsieve ON, backup
  restored, old MC backups cleaned (benchmark data deliberately kept).


Claude-Session: https://claude.ai/code/session_01Dru6wVc2ZcjiTpa6p7yJDh

Co-authored-by: Scott <scott@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reinstall dies silently: MCSS_STEAMGRIDDB_ICON_URL: readonly variable at system_integration.sh:268

1 participant