Skip to content

fix: unified 2.0.5 branch for readiness and installer regressions#222

Merged
hessius merged 19 commits intomainfrom
feat/2.0.5-unified
Mar 1, 2026
Merged

fix: unified 2.0.5 branch for readiness and installer regressions#222
hessius merged 19 commits intomainfrom
feat/2.0.5-unified

Conversation

@hessius
Copy link
Copy Markdown
Owner

@hessius hessius commented Feb 28, 2026

Summary

Unified branch for 2.0.5 readiness fixes, including installer regressions, light theme contrast, and profile generation.

Changes in this PR

Profile generation fix (latest):

  • Add settings hydration in lifespan() to populate os.environ from settings.json when env vars are empty on container restart (with masked-value guard)
  • Write hydrated values to s6 container environment for child services
  • Expand parse_gemini_error() to detect auth/API key errors and return user-friendly messages instead of raw Gemini CLI output
  • Strip noise lines (YOLO mode, etc.) from error fallback text
  • Strip display-only keys (geminiApiKeyConfigured, geminiApiKeyMasked) before persisting settings to prevent corrupted values in settings.json
  • Increase nginx proxy + subprocess timeouts from 300s to 600s for long-running profile generation
  • Add 4 new tests: auth error detection (2), settings hydration (2)

Light/dark theme tag contrast fix:

  • Replace Tailwind dark: utility classes on tags with custom CSS classes (tag-body, tag-flavor, etc.) to bypass Tailwind v4 compat mode @media(prefers-color-scheme:dark) override
  • Add explicit .dark .tag-* selectors in index.css
  • Update tags.ts and tags.test.ts for new class names

Earlier fixes (already in branch):

  • Fix /api/* route aliases for coffee generation endpoints (404 regression)
  • Add actionable frontend error mapping for profile generation failures
  • Classify profile validation and timeout Gemini errors

Validation

  • apps/server: 575 Python tests passed (test_main.py)
  • apps/server: 19 logging tests passed (test_logging.py)
  • apps/web: 251 vitest tests passed
  • root: 161 BATS tests passed
  • Profile generation verified via API (curl) and browser UI
  • CI: All workflows passing (Test Suite + Build and Publish)

Copilot AI review requested due to automatic review settings February 28, 2026 07:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR unifies two feature branches for v2.0.5: a version bump / CI Bun retry fix and a light-theme contrast fix for profile tags. It also merges governance and installer fixes from PR #221.

Changes:

  • Version bump to 2.0.5 across VERSION, apps/web/package.json, and the Bun base image in the Dockerfile
  • Installer fixes: remove unsupported --progress plain flags from all docker compose calls, add exit 1 on compose up failure, update Watchtower default host port from 8088 → 18088
  • Light-theme tag contrast fix: refactor FormView.tsx to use the shared getTagColorClass helper with category-aware, dark-mode-safe CSS classes

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
VERSION Bumped to 2.0.5
apps/web/package.json Version bumped to 2.0.5 (kept in sync with VERSION)
docker/Dockerfile.unified Bun base image pinned to 1.3.10-alpine
.github/workflows/tests.yml 3-attempt Bun setup retry with version 1.3.10 pinned across all 4 CI jobs
docker-compose.watchtower.yml Default Watchtower host port changed from 8088 to 18088 to avoid conflicts
scripts/install.sh Removes --progress plain flag; adds exit 1 on compose up failure
tests/test_install.bats New tests verifying --progress removal and installer fail-fast; updates port assertion
apps/web/src/views/FormView.tsx Tags now use getTagColorClass() for category-aware, contrast-safe styling in both themes
apps/web/src/lib/tags.test.ts Adds explicit dark-mode override assertions to tag color test suite
apps/web/src/components/SettingsView.tsx Adds watchtower_endpoint/watchtower_error to interface; displays error inline
apps/server/api/routes/system.py Introduces _probe_watchtower_api helper probing 4 known Watchtower endpoints; refactors get_update_method and trigger_update to use it
apps/server/api/routes/profiles.py Adds data URI decoding, settings IP fallback, and explicit httpx.TimeoutException/HTTPError handlers
apps/server/test_main.py New tests for TestUpdateMethodEndpoint and five new TestImageProxyEndpoint tests
.github/copilot-instructions.md Adds session governance section establishing tasks.md precedence and release authorization rules

Comment thread apps/web/src/components/SettingsView.tsx Outdated
Comment thread apps/server/api/routes/system.py Outdated
Comment thread apps/server/api/routes/profiles.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Comment thread .github/copilot-instructions.md
Comment thread apps/server/api/routes/system.py
Comment thread apps/web/e2e/app.spec.ts Outdated
Comment thread apps/server/api/routes/system.py Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@hessius
Copy link
Copy Markdown
Owner Author

hessius commented Feb 28, 2026

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 28, 2026

@hessius I've opened a new pull request, #223, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 7 commits February 28, 2026 10:47
…review feedback

Co-authored-by: hessius <1499030+hessius@users.noreply.github.com>
fix: address review comments — copilot-instructions version, system.py docstring, E2E badge locators
Tailwind v4 compat mode generates @media(prefers-color-scheme:dark) blocks
that override the app's .dark class toggle when the OS is in dark mode.

Replace all Tailwind dark: utility classes on tags with custom CSS classes
(tag-body, tag-flavor, etc.) in index.css using explicit .dark .tag-*
selectors. This ensures proper contrast in both light and dark themes.

- Add tag-body, tag-flavor, tag-process, tag-origin, tag-roast, tag-style
  CSS classes with light/dark variants
- Update tags.ts to use new CSS classes instead of Tailwind utilities
- Update tags.test.ts for new class names
- Remove unused safelist entry from tailwind.config.js
…ror handling

Add settings hydration in lifespan to populate os.environ from settings.json when env vars are empty. Expand parse_gemini_error to detect auth errors and return user-friendly messages. Strip display-only keys before persisting settings. Increase timeouts from 300s to 600s. Add 4 new tests.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.

Comment thread apps/server/services/gemini_service.py Outdated
Comment on lines +376 to +384
# Check for long-running generation / model stall patterns
if (
'timed out after' in error_text_lower
or 'deadline exceeded' in error_text_lower
or 'took too long' in error_text_lower
):
return (
"Profile generation timed out. Please retry; if this repeats, "
"reduce prompt complexity or use a stronger Gemini model."
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The authentication error check at step 3 in parse_gemini_error includes 'timeout' in the network/connection errors check (line 357): if 'network' in error_text_lower or 'connection' in error_text_lower or 'timeout' in error_text_lower. This check runs before the new timeout check at lines 377–385.

If a Gemini CLI error message contains both 'timeout' and 'timed out after' (e.g. "Gemini CLI timed out after 600s"), the 'timeout' substring will match the network/connection check first, returning "Network error connecting to Gemini API" instead of the more specific "Profile generation timed out" message. The timeout-specific check at lines 377–385 will never be reached for such errors.

Consider moving the timeout-specific check (lines 376–385) before the general network/connection check, or removing 'timeout' from the network/connection condition so it falls through to the more specific check.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8433d96 — moved the timeout-specific check (timed out after, deadline exceeded, took too long) before the general network/connection check so the more specific message is returned.

Comment thread apps/server/main.py Outdated
Comment on lines +88 to +97
s6_env_dir = "/var/run/s6/container_environment"
if not os.path.isdir(s6_env_dir):
return
try:
with open(os.path.join(s6_env_dir, var_name), "w") as f:
f.write(value)
except Exception:
pass # best-effort; logged at caller site if needed


Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _write_s6_env function introduced in main.py (lines 82–95) is a duplicate of the already-existing _update_s6_env function in apps/server/api/routes/system.py (line 1140). Both functions write a value to /var/run/s6/container_environment/. The version in system.py is more complete (it logs a debug message when the dir is absent, and logs success/failure with a request_id). This duplication increases maintenance burden. Consider extracting both into a shared utility module (e.g., utils/s6_env.py) or importing _update_s6_env from system.py in main.py.

Suggested change
s6_env_dir = "/var/run/s6/container_environment"
if not os.path.isdir(s6_env_dir):
return
try:
with open(os.path.join(s6_env_dir, var_name), "w") as f:
f.write(value)
except Exception:
pass # best-effort; logged at caller site if needed
# Delegate to the shared implementation in api.routes.system to avoid
# duplicating s6 environment update logic in multiple places.
try:
from api.routes.system import _update_s6_env
except Exception:
# If the route module cannot be imported (e.g. during early startup
# or in restricted test environments), fall back to a no-op to avoid
# breaking application startup.
return
_update_s6_env(var_name, value)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8433d96 — extracted the shared logic to utils/s6_env.py with the more complete implementation (logging, debug messages). Both main.py and system.py now delegate to utils.s6_env.update_s6_env().

Comment on lines +89 to +91
"generateFailed404Route": "Failed to generate profile: The server route was not found (404). This is often a reverse-proxy/API path mismatch — verify your proxy forwards /api/* to MeticAI.",
"generateFailedTimeout": "Failed to generate profile: The AI request timed out. Please retry; if this repeats, reduce prompt complexity or try a stronger Gemini model.",
"generateFailedValidation": "Failed to generate profile: The AI generated an invalid profile schema. Please retry — a second attempt often succeeds.",
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new translation keys generateFailed404Route, generateFailedTimeout, and generateFailedValidation are only added to the en and sv locale files. The de, es, fr, and it locales are missing these keys. While i18next will typically fall back to the en locale, users with those languages configured will see English strings rather than their native language for these new error messages. The missing keys should be added to all locale files.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8433d96 — added generateFailed404Route, generateFailedTimeout, and generateFailedValidation keys to all four missing locales (de, es, fr, it) with proper translations.

- Extract s6 env helper to shared utils/s6_env.py, update main.py and system.py to delegate to it
- Move timeout-specific check before general network/connection check in parse_gemini_error to avoid incorrect match ordering
- Add missing i18n translation keys (generateFailed404Route, generateFailedTimeout, generateFailedValidation) to de, es, fr, it locales
@hessius hessius merged commit 934a933 into main Mar 1, 2026
8 checks passed
@hessius hessius deleted the feat/2.0.5-unified branch March 1, 2026 00:00
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.

3 participants