Skip to content

fix(installer): persist the installer tier as TIER in .env - #6617

Open
IronicRayquaza wants to merge 1 commit into
Osmantic:mainfrom
IronicRayquaza:fix/installer-persist-tier
Open

IronicRayquaza wants to merge 1 commit into
Osmantic:mainfrom
IronicRayquaza:fix/installer-persist-tier

Conversation

@IronicRayquaza

@IronicRayquaza IronicRayquaza commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #7325

Update: Rebased onto current main (2026-10-04); Windows and macOS generator tests re-run and passing.

Summary

TIER is declared in .env.schema.json and read back by several components, but no installer ever writes it. The Linux phase 06, macOS and Windows env generators only put the tier into a header comment:

# Tier: 1 (Entry Level)

The readers therefore see an empty value, or fall back to their own default:

Reader Effect today
ods status-json (--arg tier "${TIER:-}") reports "tier": "", although its help promises mode/tier/model
ods mode, ods model current (grep "^TIER=") and ods.ps1 model current never show a tier
ods-cli _regenerate_compose_flags, host agent TIER = env.get("TIER", "1") always pass --tier 1 to resolve-compose-stack.sh
bootstrap-upgrade.sh compose-flags recovery falls back to tier 1

TIER only appeared after a later host-agent model activation wrote it. This also matters for the open tier-0 memory-overlay fixes (#6077 / #5467): they resolve the overlay from the tier, and the tier never reaches the resolver.

Fix

Write TIER=<installer tier> beside MODEL_PROFILE in:

  • installers/phases/06-directories.sh (TIER=$(dotenv_value "${TIER}"))
  • installers/macos/lib/env-generator.sh
  • installers/windows/lib/env-generator.ps1

On reinstall it is regenerated from the installer's tier, the same way LLM_MODEL and GGUF_FILE already are.

AI Assistance

Claude Code (Claude Opus 5.5) found the defect in an audit of the live main tree. It added the assertions first; the macOS and Windows generator tests failed on main with "must persist TIER". It also drafted the fix and this description. I reviewed the diff and the validation.

Release Lane

  • Stable hotfix targeting release/2.6.x
  • Mainline change targeting main
  • Next-minor work targeting the next feature/minor release
  • Not sure; reviewer should help classify

Changed Surface

  • Docs only
  • Tests only
  • Dashboard UI
  • Dashboard API / host agent
  • Installer / bootstrap / lifecycle
  • Docker Compose / service manifests
  • Model routing / Hermes / capabilities
  • Network exposure / auth / proxy
  • Dependencies / runtime wiring

Risk And Validation

  • Risk level: Low. It adds one schema-declared key to each generated .env. No Compose file interpolates TIER, and every reader already expects it.
  • Validation run:
    • git diff --check
    • Focused tests listed below

Commands/results:

$ bash tests/test-macos-env-schema.sh                  # on main, with the new assertion
[FAIL] tier 1 .env must persist TIER for ods-cli and the host agent
$ bash tests/test-macos-env-schema.sh                  # with the fix: all PASS, tiers 1 and CLOUD validate against the schema

$ pwsh tests/test-windows-llama-memory-budget.ps1      # on main: "Generated .env does not persist TIER"
$ pwsh tests/test-windows-llama-memory-budget.ps1      # with the fix: [PASS]

$ bash tests/smoke/installer-env-smoke.sh              # with the fix
  ✓ .env validates against schema
  ✓ Installer tier is persisted as TIER
  ✓ No duplicate keys in .env

$ shellcheck --exclude=SC1091,SC2034 -S error <changed .sh files>   -> clean

Operational Change Check

  • This is not an operational change.
  • This is an operational change and validation is recorded above. It adds one line to each generated .env, and all three generators are exercised by existing tests that also validate the output against .env.schema.json.

Notes For Reviewers

I ran the smoke test under Git Bash on Windows. All .env assertions passed; its final grep -ohP function-resolution check needs PCRE grep, which Git Bash lacks, so that check exits early there. It runs normally on the Linux CI image.

🤖 Generated with Claude Code

Lightheartdevs added a commit that referenced this pull request Sep 26, 2026
A live sample on the 16 GB WSL laptop (Qwen3.5-9B, 64K, b9014) showed
that a Pixel conversation is cached with all its context checkpoints: a
48,465-token prompt with 32 checkpoints took 2,464 MiB, a 52,019-token one
2,523 MiB. A quarter of the headroom (2304 MiB) is below one such entry,
so the next short prompt saved after it evicts it (b9014 evicts
oldest-first once the total exceeds the limit). A third of the memory
left after 6 GiB gives 3072 MiB in that VM, which is also a quarter of
the 12G container limit of its runtime profile: one full agent
conversation plus a few short prompts. Hosts from about 30 GiB keep
llama.cpp's default unless their container limit is smaller.

Also keeps the Windows test's new assertions away from the lines #6617
changes, and restores LF endings in the new Python test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
All three env generators wrote the tier only into a header comment
("# Tier: ..."), never as TIER=. Everything that reads it back got an
empty value or its own default: `ods status-json` reports "tier": "",
`ods mode` and `ods model current` (ods-cli and ods.ps1) never show a
tier, the host agent and ods-cli pass --tier 1 to the compose resolver,
and bootstrap-upgrade falls back to tier 1 when it re-resolves the
stack. The host agent only wrote TIER after a later model activation.

Write TIER beside MODEL_PROFILE in the Linux phase 06, macOS and Windows
env generators (it is already declared in .env.schema.json), and assert
it in the installer env smoke test, the macOS env schema test and the
Windows env generator test.

Co-Authored-By: Claude Opus 5.5 <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.

Installers never write TIER to .env

1 participant