6 test files had hardcoded locale counts/lists that broke when
the Italian locale block was added:
- test_issue1488_composer_voice_buttons.py: added 'it' to LOCALES,
replaced assert count == 9 with len(self.LOCALES)
- test_issue1560_password_env_var_lock.py: added 'it' to LOCALES
- test_1560_password_env_var_no_op.py: added 'it' to EXPECTED_LOCALES
- test_login_locale_parity.py: bumped floor from 9 to 10, added 'it'
- test_stage268_opus_followups.py: bumped floor from 9 to 10
(cherry picked from commit f5e42cec9bc77354c594321b20ba83055d2e3cf7)
Adds complete Italian translation for all ~280 UI strings in static/i18n.js
and the login page strings in api/routes.py (_LOGIN_LOCALE).
Ordered alphabetically: en → it → ja in both files.
Preserves all JS function templates, template literals, and plural forms.
(cherry picked from commit c66e04b190e960de2a2902157261a5e407501054)
Maintainer review on #1895 asked for two test additions:
TestApiWireFormat — stands up a tiny http.server stub on a free port,
points WEBUI_URL at it, and captures (path, body, headers) of every
request the MCP issues:
- test_rename_session_posts_to_canonical_path: locks /api/session/rename
URL + body shape so a typo in the path or field names cannot slip
through validation-only tests.
- test_move_session_posts_to_canonical_path: same for /api/session/move
including profile pre-flight against a real local project.
- test_move_session_unassign_sends_null_project_id: explicit JSON null
in the body, not an omitted key.
- test_url_built_from_env_vars: HERMES_WEBUI_HOST/HERMES_WEBUI_PORT
flow through to WEBUI_URL — would have caught the original 8788 bug.
- test_url_default_when_env_unset: default 127.0.0.1:8787 matches the
upstream contract from api/config.py:33.
TestProfileCliOrdering — locks the --profile CLI ordering invariant
(mcp_server.py:62-64): the override of _active_profile must bind before
any consumer reads it. Today this is safe because get_active_profile_name
reads the module global lazily, but a regression that latched the value
at import time would silently make --profile foo a no-op.
50/50 mcp tests pass.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Maintainer review on PR #1895 flagged that mcp_server.py duplicated the
visibility model from api/routes.py:75. Move the canonical helper into
api/profiles.py (next to _is_root_profile, on which it depends) so both
api/routes.py and mcp_server.py import the same function instead of
carrying parallel definitions that could drift as the model evolves.
- api/profiles.py: + _profiles_match (verbatim from former routes.py:75-97)
- api/routes.py: replace local definition with re-export to keep all
existing _profiles_match(...) call sites resolving
without per-call-site refactors
- mcp_server.py: drop local copy, import _profiles_match alongside the
existing api.profiles imports (line 59)
- tests: + test_profiles_match_single_source_of_truth asserts
identity (mcp.module._profiles_match is api.profiles._profiles_match
is api.routes._profiles_match) so any re-introduction of
a local copy trips the test
+ test_profiles_match_input_matrix parametrize across
the (None|''|'default'|'foo') x (None|''|'default'|'foo'|'bar')
visibility matrix per maintainer suggestion
Behaviour unchanged. Zero call-site changes anywhere in api/routes.py.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Blocker fixes from maintainer review of #1895.
WEBUI_URL: replace hardcoded 'http://127.0.0.1:8788' with HERMES_WEBUI_HOST/
HERMES_WEBUI_PORT env vars defaulting to 127.0.0.1:8787, mirroring the
contract in api/config.py:32-33. The 8788 default would have failed every
fresh upstream install — 8787 is canonical, 8788 is a local-deployment
quirk on hosts where 8787 is taken by another service.
delete_project no-auth path: remove the filesystem fallback that wrote
session_data['project_id']=None directly via os.replace(). That bypassed
_write_session_index() and left _index.json holding the stale project_id,
causing a running WebUI to keep grouping sessions under the deleted
project until something else triggered a re-compact. Even calling
Session.save() in-process would not have helped because the WebUI's
SESSIONS dict cache lives in a separate process and would overwrite our
update on its next save. The HTTP API is the only cache-safe path —
without auth we now refuse the unassign and surface a 'warning' field.
Tests: + test_delete_no_auth_refuses_unassign locks the new behaviour
(project deleted, sessions and index untouched, warning surfaced).
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Per maintainer review, replace duplicated I/O with canonical helpers
for locking, profile scoping, index consistency, and validation.
Profile scoping (#1614) enforced on all CRUD via _profiles_match
matching api/routes.py:75 semantics exactly. AI-authored, human-reviewed.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>