# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Fixed - ๐Ÿš€ The API's health grace covers its measured boot on the Pi (`start_period` 60 s โ†’ 180 s): a deploy applying one migration took 2 min 22 s from container start to the last worker ready, and `up --wait` reported a deploy that had succeeded as failed (`test_api_boot_budget_guard.py`). - ๐Ÿ›‘ A task cancelled while its database session closes now stops. Both session helpers (`get_db_context`, `get_db_session`) suppressed a cancellation landing during their shielded close, and the task carried on โ€” measured on dev, a worker reload waited more than 36 minutes for the lifetime-metrics loop, asleep again after its `cancel()`. The close now runs to its end as one task the helper owns (`write_through_cancellation`), then the cancellation propagates; and a session is closed once, where `AsyncSession.__aexit__` used to start a second close beside the first (`test_session_cancellation.py`, `test_session_close_cancellation_pg.py`). - ๐Ÿ›‘ A chat turn cancelled while its tracked spend is written now ends cancelled. The stream's `finally` shielded the spend commit and caught the cancellation, logging it as ยซ completed ยป โ€” `shield` does not wait โ€” so the turn ran on past its stream. The commit runs to its end (`orchestration/tracking_commit.py`), then the cancellation propagates; `test_no_swallowed_shield_cancellation_guard.py` refuses the shape anywhere under `src/` and flags the three sites fixed here on their former sources. - ๐Ÿ” What ends a route reaches its database session. `get_db` delegated to `get_db_session` with `async for`, which forwards nothing: for every route depending on it, a failure never reached the rollback branch (its rollback, its `db_transaction_rollback_total{endpoint="fastapi"}` count, its classified log), and the session closed only when the garbage collector finalized the abandoned generator. `get_db` now enters it as a context manager โ€” the ยซ Tx Rollbacks ยป panel (dashboard 03) counts route failures from now on โ€” and the unverified-account sweep, which iterated it too, opens `get_db_context()`; `test_no_iterated_session_dependency_guard.py` refuses the shape. - ๐Ÿ”’ The unverified-account sweep no longer logs the addresses it deletes. It read them only to log them at INFO, cut to three characters and the whole domain under a comment calling them ยซ hashed ยป, and the runtime PII filter let them through: a masked address no longer matches its pattern, and `sample_emails` is no name it knows. The sweep logs the count, like the demo account purge, and reads no address (ADR-317). - ๐Ÿ”’ The log PII filter withholds an address in every shape it takes. Measured on the filter, four went through to INFO: a full address inside a tuple, a set or a list of lists (only a list's strings and dicts were read); a masked one (`fir***@mail.test`, `fโ€ฆ@mโ€ฆ.test`); one outside ASCII (`zoรซ@mail.test` whole, `andrรฉ.martin@โ€ฆ` keeping its first name); and any value under a name beyond four exact ones (`recipient_email`, `sample_emails`). Containers are read at every depth, the pattern takes every script and the masking marks (still linear, measured), and a field named for an address hashes its text whatever its shape โ€” a count, a flag or an id under such a name stays. - โšก An uploaded HEIC picture is converted and a PDF's text extracted off the event loop (`asyncio.to_thread`), like every other PDF reader. Measured on a workstation, the longest stall of the worker's loop fell from 0.9-1.2 s to under 20 ms for a 12-megapixel HEIC, and from about 230 ms to about 20 ms for a 300-page PDF read to its last page; PyMuPDF holds the GIL during each call, so its longest one still bounds the stall. ## [3.7.0] - 2026-10-25 **A first name finds the person, what you shared shows where you shared it, any recording becomes minutes, and every step says what it did.** A first name now reaches the one connection or relationship it designates โ€” and a name that fits several people is asked about, never guessed; a skill, a plugin or an MCP server says who you shared it with and who it came from; a kept answer or a generated file can be brought back into a discussion; a relationship's records line up on one dated timeline; a WAV, MP3 or M4A recording becomes a meeting with its minutes; each step of an answer counts its calls, results and failures; a phone call's report shows what it cost; and the V15 audit is published: 7.9/10 on the committed version 3.6.0. ### Added - ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ **A first name finds the person** (ADR-180, ADR-182 and ADR-185 amendments). One rule decides what a spoken name designates in any directory (`shared/name_resolution.resolve_name`): the folded full name first, then every word said as a whole word of the name โ€” never a fragment, never an edit distance โ€”, one identity resolved, several an ambiguity asked about with the candidates (`DISAMBIGUATION_REQUIRED`, at most five). The peer tools read the accepted connections only (`agents/peer/name_directory.resolve_connected_peer`); on a partial match the relationship list only SUBTRACTS โ€” a person who is not connected and whom the name also designates turns the read into a question, a name designating only non-connected people is said (`not_a_connection`) โ€” and a merge declared on the Relations page never picks an account. The three relationship read tools resolve against the relationship list, so an unknown name answers `NOT_FOUND` instead of an empty card; the workboard's assignment applies the same rule over the connections. The list the assistant reads admits an SMS sender only where the person let the assistant read their SMS, and the peer tools end their reads before consulting it (its SMS senders can ask the contacts provider, ADR-304). Guard: `test_name_resolution_single_rule_guard.py`. - ๐Ÿค **ยซ Shared with ยป and ยซ Received from ยป under a capability's line** (ADR-350 amendment). Skills, plugins and MCP servers carry `shared_with` โ€” the recipients a sender published each one to, newest share first, in one query per page (`shared/capability_shares`), a deactivated or erased recipient unnamed โ€” drawn in a ยซ Shared with (N) ยป disclosure, an incomplete share said so; a received copy keeps ยซ Received from โ€ฆ ยท date ยป. Whether a sender may share again is ONE function, `reshare_allowed`: a published share is final for now โ€” the door stays open, no index stands in its way โ€”, asked at the preview AND at the send under the pair's lock (409 `peers_capability_already_shared`, an installation in flight counted as given, the resumption of a partial share allowed); the recipient list leaves out who already has it. The assistant's native readers never see `shared_with`. - โ™ป๏ธ **A kept answer or a generated file back in the discussion** (ADR-295 amendment). `POST /attachments/from-bookmark` attaches a bookmark as the Markdown its knowledge document reads, whatever its projection's state; `POST /attachments/from-generated` copies a live generated image or document of the caller (an image within the upload bounds, a document with its text). Both are COPIES โ€” uploads a reset removes and the TTL expires, the original untouched โ€”, sharing one store with the knowledge-document door (`attachments/copy_store.py`). The ยซ + ยป offers ยซ A bookmarkโ€ฆ ยป and ยซ A generated fileโ€ฆ ยป; a bookmark card and the gallery offer ยซ Use in the discussion ยป, a one-shot `?attach=` link that never sends anything. - ๐Ÿ—“๏ธ **A relationship's timeline** (ADR-185 amendment b). A collapsible section merges the card's dated records โ€” open commitments, calls, memories, relayed messages, text messages โ€” newest first on one line (`GET /relations/{name}/timeline` and `/lookup/person/timeline`): five keyset reads after one opaque cursor, so a record landing between two pages neither repeats nor drops one (`infrastructure/database/keyset.py`); the identity is the card's (`relations/identity_scope.py`), mails and appointments are merged within the card's own windows, and a forged cursor answers 400. - ๐ŸŽ™๏ธ **A meeting imported from a WAV, MP3 or M4A file** (ADR-258 amendment). An imported file is admitted like a recording, travels in chunks onto the same durable row (`uploading`, one per account, held by the database) and is processed like one: `GET /meetings/imports/limits`, `POST /meetings/imports`, `PUT /meetings/{id}/import/{sequence}`, `POST /meetings/{id}/import/complete`. Every bound is published before a byte is sent (`MEETINGS_IMPORT_MAX_MB`, `MEETINGS_IMPORT_CHUNK_MAX_MB`), the first chunk must start as the format it claims, ffmpeg reads it through that format's demuxer alone (`-f wav|mp3|mov`, `-enable_drefs 0`, local files only), the duration is measured โ€” and refused past the cap โ€” before any engine is paid, and an import silent for `MEETINGS_IMPORT_STALE_MINUTES` fails `import_incomplete`, its chunks deleted. `MEETINGS_IMPORT_ENABLED` switches it off; `meeting_imports_total{format,outcome}` on dashboard 27. ยซ Import ยป sits beside ยซ Record ยป on the meetings page and in the ยซ + ยป. - ๐Ÿ”ข **Each step says what it did** (ADR-133 amendment). A tool's line in the bubble and in the persisted trace counts its calls (ยซ ร—2 ยป), the results found and read, and its failures โ€” live as each ReAct call finishes (`step_key`), and per tool for a pipeline plan, a FOR_EACH counted by its items (`streaming/tool_step_outcomes.py`); the item id format is declared once (`ExecutionStep.item_step_id`). ### Changed - ๐Ÿค– **A JEV qualification reaches the model as a state, never as an instant** (ADR-351 amendment). The data block and the text line carry the labels and `current` or `expired`, decided by the code when they are shown (`classification_view`): handed `valid_until` in UTC beside a clock in the person's zone, a model told the person a label valid for another hour had expired. ยซ Unknown never means safe ยป now speaks of e-mails only, and the e-mail priority's reference time is given in the person's zone. - ๐Ÿ’ฌ A discussion bubble's buttons sit on the right, wrapping as one group. - ๐ŸŽ™๏ธ The meetings page offers ยซ Record ยป and ยซ Import ยป side by side. - ๐Ÿงญ The demonstrator's environment templates are laid out in themed sections under a table of contents (`docs/technical/DEMO_INSTANCE.md`). ### Fixed - ๐Ÿ’ถ **A phone call's report shows what it cost** (ADR-290, ADR-301 and ADR-272 amendments). Three paths archived a call's notification without the call's run id โ€” the owner call's fallback, the third-party call's debrief, the reaper's re-dispatch โ€”, so the bubble showed no cost although the synthesis had one: every call notification now leaves through one door (`telephony/call_notifications.py`, AST guard). A rewritten voice-session card tells the open tabs (ADR-320 signal), and a Live session's card restates its bill once the learning that follows the closing has spent. - ๐Ÿ“Ž Attaching a knowledge document whose text cannot be read no longer leaves its copy on disk, and the copy is made once the document's read has ended โ€” no transaction waits on the disk work. - ๐Ÿงช The TOTP tests computed their code from a naive local time, wrong during the hour a clock change repeats; they read the UTC instant. ### Tests - ๐Ÿ›ก๏ธ Guards: one name-resolution rule (`test_name_resolution_single_rule_guard.py`), one door for a call's notifications (`test_call_notification_door_guard.py`); the `streaming/service.py` size cap lowered from 1,303 to 1,245 logical lines after the step outcomes moved out. - ๐ŸŒ Browser journeys for the step counts (live and from history), the meeting import, the relationship timeline, capability sharing and bringing a bookmark back, on desktop and phone widths. - โฑ๏ธ Testing Library's waits are calibrated for the coverage run like `testTimeout` (`asyncUtilTimeout` 5 s): under full parallelism with instrumentation the suite runs about five times slower, and an optimistic rollback missed the 1 s default once in two runs. The release history's landmark test scopes each role query to its own region instead of walking the whole history twice per series. - ๐Ÿ”ข Test inventory: 53,211 backend tests collected across 3,559 files and 14,191 frontend tests across 1,139 files. ### Documentation - ๐Ÿ“š Amendments of ADR-133, ADR-180, ADR-182, ADR-185, ADR-258, ADR-272, ADR-290, ADR-295, ADR-301, ADR-350 and ADR-351; `TELEPHONY.md`, `MEETINGS.md`, `ATTACHMENTS_INTEGRATION.md`, `BOOKMARKS.md`, `PEER_CAPABILITY_TRANSFERS.md`, `EMAIL_EVENT_CLASSIFICATION.md` and `DEMO_INSTANCE.md`; the FAQ and the help corpus in six languages. - ๐Ÿ” **The V15 audit is published**: 7.9/10 across 24 areas on the committed version 3.6.0 (commit `3909d87c5`), 17 open findings โ€” one major โ€” and its register: AC-029 reopened, AC-039 closed, AC-041 and AC-043 to AC-049 new, AC-042 a positive control ([docs/audit/README.md](docs/audit/README.md)). ## [3.6.0] - 2026-10-24 **Password doors robots cannot hammer, tokens renewed once, every audit finding followed to its proof.** A password reset now answers for one account โ€” capped per account whoever asks, bound to the password it would replace, never a way into an account that signs in with Google; an operator can put Cloudflare Turnstile on sign-up, sign-in and reset; a discussion left unanswered holds the next one for an hour, not a day; and the V14 audit's remediation wave lands โ€” one refresh door for every OAuth token, a database that bounds its own lock waits and idle transactions, a notification filed delivered only once it is, alerts that reach their teams, and a public register that follows every finding to its proof. ### Security - ๐Ÿ” **A password reset answers for one account** (ADR-363). Who may receive a link is ONE decision (`auth/password_reset_policy.decide_reset`), applied when the link is asked for AND when it is used: a deleted account or an administrator receives nothing โ€” the attempt is alerted instead โ€”, an account that signs in with a provider and has no password receives a notice naming it, never a link that would create a password, and every other account a link. An account's e-mail budget holds whatever address asks (`PASSWORD_RESET_ACCOUNT_INTERVAL_SECONDS`, `PASSWORD_RESET_ACCOUNT_DAILY_MAX`, on the existing `RedisRateLimiter`, in a `USER_RUNTIME` key family a conversation reset never frees), the short window asked first so hammering the route cannot spend a victim's day. A link carries the account id and an HMAC of the stored password hash: a password changed since, or an account re-created at the address, retires it. The Security settings state the real way back (`password_recovery` on `GET /auth/step-up/status`, ADR-143 amendment). `password_reset_requests_total` and `password_reset_confirmations_total{outcome}` (every series present at zero), dashboard 09, two core alerts โ€” `PasswordResetAbuse` and `RegistrationBurst`, their thresholds per environment (`ALERT_CORE_PASSWORD_RESET_THROTTLED_PER_HOUR`, `ALERT_CORE_REGISTRATIONS_PER_HOUR`) โ€” with their runbooks, promtool cases and evidence recipes; a rate-limit `key_prefix` label carries no client address and no account id. - ๐Ÿ—๏ธ **An administrator's way back is server-side** (ADR-363 amendment): `python -m scripts.data.set_password --email โ€ฆ` (`task db:set-password`) sets the password, then signs every device out. The first administrator of a self-hosted instance has a password and, under the new rule, no reset link: this is its way back. - ๐Ÿค– **A Cloudflare Turnstile anti-robot check on the password doors** (ADR-364), off until the operator brings a widget (`TURNSTILE_ENABLED`, `TURNSTILE_SITE_KEY`, `TURNSTILE_SECRET_KEY`; the boot refuses the switch without both keys). Sign-up, sign-in and the reset request carry a token (`X-LIA-Turnstile-Response`), checked after the per-IP limiter (`auth/turnstile_gate.py`), valid only for THIS door on THIS instance's pages. `TurnstileClient` never raises and bounds each of its two attempts whole (`TURNSTILE_VERIFY_TIMEOUT_SECONDS`). When Cloudflare gives no usable answer only the sign-in proceeds โ€” a tokenless one too, while the server's own view of Cloudflare confirms the outage (`TURNSTILE_REACHABILITY_TTL_SECONDS`, one shared probe); a sign-up or a reset request is refused `turnstile_unavailable`, a refused token `turnstile_failed`, and a testing key in production counts as no answer (`TurnstileUnavailable` alert, `ALERT_CORE_TURNSTILE_UNAVAILABLE_PER_15M`). The site key reaches the sign-in pages alone (`PublicAuthFeaturesResponse`), the widget runs `interaction-only` in the page's theme and language, the CSP admits Cloudflare's challenge host (ADR-098 amendment), and the privacy policy (v1.2) names the check in six languages. - ๐Ÿ“ฆ **The dependency advisories closed before the tag**: `zod` 4.6.7 (GHSA-mrhx-c7xc-m3w5, high, fixed from 4.6.6 โ€” validation of an oversized constrained collection could exhaust memory), raised as the manifest's floor (ADR-331), and `vitest` / `@vitest/coverage-v8` 4.1.12 for two moderate `@vitest/mocker` advisories (GHSA-qxg6-89mg-rqv8, GHSA-xp26-3454-mjgp) of the test toolchain, their two dependency-watch acceptances removed. Two repository tools no workspace audit reads were behind too: the landing film's Remotion project (`tools/lia-motion`) forces the same `zod` over Remotion's 4.5.4 pin and floors `fast-uri` at 3.1.9 (four advisories) through npm `overrides`, and the wake-word GPU toolbox floors `brotli` at 1.2.1 (GHSA-9v8h-qqgm-4m35, critical, an out-of-bounds write in the decoder). In that toolbox, `datasets` (GHSA-379c-qx7v-6h59), Pillow and fsspec stay held by VoxCPM's and gradio's caps โ€” a developer tool, never on the API's interpreter nor on the Pi. ### Added - ๐Ÿ’ฌ **A discussion left unanswered holds the next one for an hour, not a day** (ADR-358 and ADR-359 amendments): `DISCUSSION_ATTENTION_UNANSWERED_OPENING_MINUTES` (60; the 24-hour reply window is unchanged), the next publication supersedes an opening still pending โ€” after binding any reply a channel archived meanwhile โ€”, a run that never starts names why on its counter outcome and in `discussion_run_not_started`, and the activity panel says when LIA is waiting for your reply (`DiscussionActivity.awaiting_reply`). - ๐Ÿ“‹ **A public register of the audit findings** (AC-031): `docs/audit/findings_register.json`, verified by `scripts/audit/findings_register.py` in `task lint:docs` โ€” every AC finding of the reports exists in it, a closure or a remediation carries its proof โ€” and `task release:check` refuses a P1 past its horizon unless deferred. This release remediates eighteen findings of the V14 revision; they await the next audit's verification. - ๐Ÿงฐ **The installer offers the anti-robot check** (ADR-364): on an instance reached on a public domain it asks for the Turnstile site key and secret key together โ€” both or neither, hidden at the prompt, refused when they are Cloudflare's testing keys โ€” writes them and `TURNSTILE_ENABLED=true` to the private `.env` alone, never re-asks them on a resume and keeps an operator's configuration on a run that skips them (`scripts/install/turnstile.py`). - ๐Ÿ“ˆ **The discussion tables are measured before any retention** (ADR-358 amendment, AC-034a): `proactive_discussion_table_rows` and `proactive_discussion_table_bytes`, drawn on dashboard 13, before a retention rule is decided. ### Changed - ๐Ÿ”„ **One refresh door for every OAuth token** (ADR-302 amendment, AC-029; notes in ADR-021, ADR-029 and ADR-047). Legacy connectors, shared grants and Hue Remote renew through `connectors/oauth_refresh.py`: one exchange per token across callers and workers (a single flight in a worker, an owner-token claim across workers, a published verdict โ€” an unexpected failure included), no transaction open across the provider call, a write conditioned on the token it started from and bounded in its wait for the row (`OAUTH_REFRESH_WRITE_LOCK_TIMEOUT_MS`), an `invalid_grant` re-verified before anyone is disconnected; a caller that owns its session reads (`read_connector_credentials`), then asks `fresh()`. `OAuthLock` and `OAuthGrantRuntime` are gone, `oauth_refresh_outcomes_total{kind,outcome}` and `oauth_refresh_flights_total{kind,how}` replace the lock series and `connector_token_refresh_total` on dashboard 10, and only `oauth_refresh_exchange.py` sends `grant_type=refresh_token` (guarded). - ๐Ÿ—„๏ธ **The database bounds its own waits** (ADR-304 amendment, AC-028): every application connection starts with `DATABASE_LOCK_TIMEOUT_MS` (30 s) and `DATABASE_IDLE_IN_TRANSACTION_TIMEOUT_MS` (5 min) (`database/server_bounds.py`; the migration engine carries none); each bound reached is counted (`db_bound_reached_total`), drawn on dashboard 03 and alerted (`DatabaseBoundReached`, with its evidence recipe). - ๐Ÿ“ฌ **A notification is delivered when it is** (ADR-263 amendment, AC-003): `NotificationResult.durably_delivered` โ€” archived, pushed or sent on a channel, never an SSE event alone โ€” is the one verdict. The five consumers that file ยซ delivered ยป (the phone reapers, the return synthesis, the phone relay, peer messages, diagnostics) pass `require_durable=True`, count a failure on a session of their own and read the archive only after its commit (guard `test_durable_delivery_guard.py`). - ๐Ÿ”” **Alerts reach their teams** (ADR-119 amendment, A07, AC-004): ONE Alertmanager template whose optional blocks disappear when unconfigured; severity routes continue to the team receivers, deduplicated; an audience route no loaded alert reaches fails the build unless it is declared dormant with its reason โ€” the security route is, until a loaded alert carries its component; `task test:alertmanager` runs the production image's real entrypoint against a routing matrix with amtool. - ๐Ÿ“Š **Every panel reads a produced series** (ADR-178 amendment, AC-006): a reverse guard, panel โ†’ producer, in `lint:observability`. Dashboard 26's cost and latency panels read two gauges the hourly rollup computes in PostgreSQL over the North Star's useful set (`product_outcome_cost_eur_mean`, `product_outcome_latency_p50_seconds`); dashboard 14 loses its two hybrid-search panels, whose producer left in v1.25.30 (ADR-168), and its row becomes ยซ BM25 Index Cache (RAG Spaces) ยป. The product freshness alert `ProductAggregatesStale` joins the loaded core (warning, `ALERT_CORE_PRODUCT_AGGREGATES_STALE_SECONDS`, its runbook); the three product behaviour alerts stay unloaded, re-decided by 2026-12-15 on a read-only measurement of production. - ๐Ÿงต **Nothing blocking on the event loop** (AC-035): Ruff ASYNC2 enforced on `src`, its fifteen sites fixed; speech-to-text uploads stream through `infrastructure/multipart_upload.py`. - ๐Ÿงช **The coverage floor holds where the code is executed** (ADR-113 amendment, AC-030, AC-032): the floor applies to the unit and integration suites together (`task test:backend:coverage`, combined strictly), the lines a change adds are held at the floor in CI (`task test:backend:diff-coverage`), and the doctrine is written once, in `GUIDE_TESTING.md`. - ๐ŸŒ **Every new document is in English** (AC-039a): the frozen list of French documents only shrinks (`scripts/audit/doc_language.py`, in `task lint:docs`; `task docs:language:update` removes a translated or deleted document from it, never adds one). - โš™๏ธ **An env template states the code's default, or why it differs** (AC-036, guard `test_env_template_parity_guard.py`): every line states the default, omits the key, or says why it differs (`# โ€ฆ โ€” differs from default: `). `.env.example` and `.env.prod.example` now carry the values production runs: a configuration copied from them switches on, among others, account export, detached generation, self-diagnosis, the Live mode, Gmail push and push wakes, learned habits, open loops and moments, the register's hash chain, the sandbox's network runs and the ReAct cross-turn cache, with production's budgets and bounds โ€” a discussion run may spend 5.00 USD instead of 0.10, the radio 4 EUR a day instead of 2 โ€”, while product analytics stays off, written as differing from production. The minimal template the installer starts from no longer switches detached chat generation off (ADR-117): a new guided installation runs it, like the code's default and production, and `BACKGROUND_RUNS_ENABLED=false` still brings back the inline path. A running instance's `.env` is untouched. ### Fixed - ๐Ÿš€ The web image's build no longer misses a module a type-checked test imports: `prepare-prod.ps1` stages them (`$webImportedModules`), and `test_prepare_prod_web_imports_guard.py` derives the list from the imports and refuses a stale entry. - ๐Ÿ›‘ The graceful shutdown waits, bounded, for the tasks it cancels (A05); Hue clients are closed on every path (A04); the Docker build context leaves out `.next-*` dists (A03); a refused rule set is cached with an exponential wait instead of being retried every pass (A16, reason `rules_refused`); the peer message delivery commits its reads before the model answers (ADR-304); error logs carry an error's type, never its text (ADR-317). - ๐Ÿงฐ The pre-commit hook's `.env.example` check no longer asks for what a repository instrument reads: `scripts/audit/` reads its runner's environment (GitHub's `GITHUB_ACTIONS`, the `DIFF_COVERAGE_BASE` the CI hands the diff coverage), never an instance's, so it leaves the scan by location โ€” a runtime read of the same name is still caught. ### Removed - ๐Ÿงน `OAuthLock`, `OAuthGrantRuntime` and `OAUTH_LOCK_TIMEOUT_SECONDS`, with the five `oauth_lock_*` series and `connector_token_refresh_total`; `NotificationResult.success` and `error`; `cancel_all_background_tasks`; the finance alert route, its receiver, its e-mail template and `ALERTMANAGER_FINANCE_TEAM_EMAIL` โ€” no loaded or dormant alert ever reached it (the dormant budget alerts carry `component: cost`), so the variable can leave an `.env.alerting`; the e-mail-only Alertmanager template, its Python validator and webhook matrix (superseded by `task test:alertmanager`); dashboard 14's two `memory_hybrid_search_*` panels; six dead MyPy codes and twelve unused ignores (A14a). ### Tests - ๐Ÿ›ก๏ธ Guards for the findings register, the diff coverage, the coverage union, the durable delivery, the single refresh sender, the env template parity, the document language, the `as unknown as` ratchet (AC-037) and the web bundle's imports; a pytest watchdog (`faulthandler_timeout`) and `timeout-minutes` on every CI job (AC-033a); two tests that never ran now run (AC-033b); one CPU-growth oracle for every linearity guard (ADR-326 amendment, A12); five UI primitives back in the frontend coverage (A13, AC-040); `AssistantAvatar`'s decisions extracted (A15); the `conversations.service` MyPy override removed (A14b, partial). - ๐Ÿ”ข `llms.txt` quotes its metric, ADR and release counts through the release tooling: three `CountSurface` entries in `scripts/release/version_surfaces.py`, kept by `task release:sync-counts` and refused stale by the version-surface guard โ€” it still said 630 metrics, 360 ADRs and 286 releases. - ๐Ÿ”ข Test inventory: 53,014 backend tests collected across 3,542 files and 14,114 frontend tests across 1,128 files; the installer suite runs 285. ### Documentation - ๐Ÿ“š ADR-363 and ADR-364, and amendments of ADR-021, ADR-029, ADR-047, ADR-098, ADR-113, ADR-119, ADR-143, ADR-178, ADR-263, ADR-302, ADR-304, ADR-326, ADR-358 and ADR-359; the `PasswordResetAbuse`, `RegistrationBurst` and `TurnstileUnavailable` runbooks; the authentication, security, CI/CD, diagnostics and proactive-discussions documents; the audit protocol and public report point at the register; the FAQ and its knowledge corpus, the privacy policy, the public presentations and the living maps, in six languages. - ๐Ÿ“ Public counters re-measured at the source: 67,000+ inventoried tests, 634 Prometheus metrics, 362 ADRs and 288 releases โ€” `llms.txt` and the Story page's meta description now quote theirs through the release tooling. ## [3.5.1] - 2026-10-23 **Notifications that no longer repeat themselves.** An SMS is now personal data like an email: a proactive message written while an SMS sat in LIA's context is no longer set apart, so the next decision reads it back again and the same birthday is announced once, not at every check. ### Fixed - ๐Ÿ” **The same subject announced at every heartbeat tick** (ADR-357 amendment 2026-10-23). A notification written while an SMS sat in the decision's context was marked private and withheld from the next decision's recent window โ€” the only guard against repeating a subject the model had already raised. An SMS stays an unmentioned candidate for its whole summary window, so on an account that receives SMS nearly every notification was withheld: measured in production, 21 of the 24 notifications sent to the affected account since 2026-10-20, and one birthday announced six times between 21:07 and 13:29 the next day, against one or two birthday notifications a day over the ninety days before. The same afternoon gave the counter-proof: the first unmarked announcement reached the window and the next decision chose another subject. The proactive discussions had the same blind spot: an opening an SMS informed never came back to their opening history. ### Changed - ๐Ÿ“ฑ **An SMS in view is treated like an email** (owner decision, ADR-357 amendment). A heartbeat notification drawn from a context holding an SMS shows its words in the push, reaches the external channels, airs on Radio to a listener alone, is kept for conversational continuity, enriches an interest-centred notification and is read back by the next decision โ€” like a notification drawn from mail. A proactive discussion is private when it touches a sensitive topic (health, relationships, financesโ€ฆ), whatever the source of its facts, and no longer because the run read an SMS. Unchanged: the separate assistant consent, the offering of unmentioned messages only, the mention bookkeeping after a successful delivery and the content-free reception push. Withdrawing the consent stops every new read; a notification already sent keeps its words, as one drawn from mail does once its connector is removed. ### Removed - ๐Ÿงน The SMS private mode's plumbing: `heartbeat_notifications.sensitive_context` (migration `213b9ac595c5`, applied at startup), the window filter `get_recent_by_user(for_context=โ€ฆ)`, `sms_privacy`, the dispatcher's `privacy` parameter and `ProactiveTaskResult.privacy` (the dispatcher, the runner and the task result are back to their shape before the SMS lot), `proactive_discussions/privacy.py`, `OpeningDraft.sms_context` and its validator, the history's SMS exclusion and the Radio reader's marker filter (discussions never reach Radio: they are excluded by their type). ### Tests - ๐Ÿงช Each change was first written as a failing test: a notification sent with an SMS in view is stored for continuity and read back by the recent window (PostgreSQL), the runner's own door delivers it with its words and to the external channels, an interest-centred notification is enriched with an SMS in view, a discussion run that read an SMS publishes an ordinary opening that returns as prior wording, and Radio reads a heartbeat archived with the retired marker like any other. ### Documentation - ๐Ÿ“š The ADR-357 amendment and the ADR-358 note; the SMS ingestion and qualification documents, proactive discussions, Radio, the index, the README; the FAQ, the proactive-notifications and privacy articles and the How guide in six languages; the knowledge corpus. ## [3.5.0] - 2026-10-23 **Follow-ups read back from the cache, a first dashboard that starts simple, hand-overs that name both ends.** On Claude, the next turn reads its whole history back from the provider's cache โ€” for an hour when a person is waiting โ€” and every write is billed at its real price; a new account opens on the weather and occasional exchanges; a ticket's history says who held it before and after; the phone gets the whole width; and the technical audit publishes its counter-review, 7.8/10. ### Added - โšก **Claude's prompt cache across turns** (ADR-362). In a tool loop, the history's end becomes a read point: the next turn reads its whole history back instead of writing it again (measured on two generations: 439 tokens written against 1,685). In frequent exchanges, a turn a person waits for writes its two cross-turn read points โ€” the static prefix and the history's end โ€” for Claude's one-hour lifetime: after a seven-minute pause, the next turn's first call read 144,376 tokens back and cost 89 % less. The hour is billed at its own rate (2x the input price) through every pricing door. A streamed response names it at its start only, which a stream hook now keeps (`providers/anthropic_hooks.py`); a start that names nothing is counted (`llm_cache_write_breakdown_missing_total`) and alerted (`LLMCacheWriteLifetimeUnreported`, runbook and self-diagnosis evidence included). Each call records its cache writes (`token_usage_logs.cache_write_tokens` and `cache_write_extended_tokens`, migration `6b7fe9493921`), the Article-12 technical extraction exports them and dashboard 05 draws the writes by lifetime. An earlier turn's thinking goes back to the Claude model that wrote it on a generation that keeps it without binding it to the conversation (`ClaudeSurface.preserves_prior_turn_thinking`); every other earlier block is removed under a named, counted reason. Two operator switches, both on: `PROMPT_CACHE_EXTENDED_TTL_ENABLED` and `PRIOR_TURN_THINKING_REPLAY_ENABLED`. `task llm:cache:probe` measures the design against the API under a USD budget. - ๐ŸŒค๏ธ **A new account starts simple** (ADR-311 and ADR-307 amendments). One declaration, `auth/new_account_columns.py`, spread by the three sign-up doors โ€” an e-mail registration, a first Google sign-in and the installer's first administrator โ€” starts every new account in occasional exchanges and, where the instance serves the weather on its own key, on a dashboard showing the weather card alone; the other cards wait, switched off, in the grid settings. The starter checklist opens on the home address wherever the deployment can save one (`/config.features.home_address_enabled`), and a weather card that misses an address says so (`location_not_configured`) and points to the Location settings rather than to the connectors. Existing accounts keep what they had. - ๐Ÿ” **Every hand-over in a ticket's history names both ends** (ADR-276 amendment): ยซ Held by: Me โ†’ LIA ยป, written by one function (`workboard/history.holder_fields`) for the screen, the chat, a run handing a ticket back and a connection that ends; a ticket created straight for LIA or a connection names its first holder. ### Changed - ๐Ÿ“ฑ **The phone gets the whole width** (ADR-177 amendment). Below 880 px, a table, card or code bubble takes its whole column โ€” a short answer stays a short bubble โ€” under a stylesheet guard; an empty Home card shrinks to its title and its sentence; on a relationship card, every action button takes the sheet's full width, its label on the left. - ๐Ÿ—บ๏ธ **Position, rearranged** (ADR-356 amendment). On a wide card the places sit in a column beside the map, centred on its height and scrolling inside it from the first place; the map offer is one centred block with its cost underneath; the stage takes the panel's corners; and the details window is placed again after every fit, so a first selection whose route arrives late no longer leaves it badly placed. - โœ‰๏ธ **Gmail previews read as text** (ADR-287 amendment): decoded once at the client's edge โ€” ยซ J'ai ยป now reads ยซ J'ai ยป โ€” with a newsletter's invisible padding dropped and a word that legitimately carries a joiner left as written; a relationship's e-mail excerpt shows up to four lines. - ๐Ÿงฉ **One repair chain for every structured-output door** (ADR-100 amendment). The auto-tool call โ€” the only door of a Claude that refuses a forced tool โ€” now repairs and counts like the forced one, and a JSON-mode answer repairs absent values too. On a model that forbids extras, an undeclared key holding nothing is dropped (`absent_values_dropped`) instead of refusing the whole answer: a query analysis refused for an empty note had sent its turn back to a conversation without tools. - ๐Ÿงฑ Relationship and knowledge-space cards end on the same footer rule as the skill and MCP cards. ### Security - ๐Ÿ” **Black โ‰ฅ 26.10.1 as a manifest floor** (ADR-331): CVE-2026-114134 lets the GitHub Action bundled with Black install a version read from an unvalidated `pyproject.toml` setting. LIA never runs that Action โ€” Black comes from the development lockfile alone โ€” but the dev lock carried the affected release, and the backend audit refuses it. Formatting is unchanged (7,476 files). ### Fixed - ๐Ÿ” **A failed structured-output call is said as itself** (ADR-100 amendment 2026-10-23). A provider error on the auto-tool door โ€” a 503, a 529, a 429, a refused connection โ€” used to become a cause-less ยซ produced no valid tool call ยป, counted as the model's rejection and invisible to the proactive discussions' backoff. It is now `StructuredOutputCallError`, raised from the provider's error by the three doors where a call fails and counted `call_failed` (dashboard 05). The retry wrapper leaves a client that retries by itself (the vendor SDK's `max_retries`) to its own attempts: one 503 costs three requests instead of nine. An unusable answer is still retried, and a client with no retry of its own keeps the wrapper's loop. - ๐Ÿ“ˆ The ReAct loop's model calls reach every Prometheus LLM metric: the node now hands them the per-node metrics handler every other node attaches. - ๐Ÿ”‡ A structured-output refusal no longer quotes the first 120 characters of the model's arguments at WARNING (ADR-317): the log names the parser's verdict and the schema paths, never a refused value. ### Removed - ๐Ÿงน **Code no entry point reached** (ADR-194 amendment), proven by walking every caller up to a registered tool, a route or a job: 31 definitions of `formatters.py` (`ContactsFormatter`, three date formatters, ten Gmail extractors), the eleven functions of the former contact-detail path in `google_contacts_tools.py`, `agents/utils/email_enricher.py`, the four translated messages only they read, and the 66 tests that exercised nothing else. Nothing changes for a person: none of these paths ran. ### Tests - ๐Ÿงช PostgreSQL proofs for the two cache-write columns and for the installer's first account starting like every new account; unit coverage of the Claude payload policy (the history read point, the lifetimes, the hour never placed after a caller's own breakpoint), the stream hook, the prior-thinking decisions, the cache horizon's scope across `astream_events`, the auto-tool repairs and the query-analysis door, the keyless ceiling, the starter checklist, the weather setup line, the hand-over history and the Position placements. - ๐Ÿ›ก๏ธ New guards: a stylesheet test refusing any rule that narrows a phone bubble below its column and pinning the Position list's placement; `test_cache_write_reaches_every_price` holds every turn door to the hour's writes and names the cache horizon's one writer; two promtool cases for the new alert. ### Documentation - ๐Ÿ“š ADR-362, and amendments of ADR-100, ADR-177, ADR-194, ADR-276, ADR-287, ADR-306, ADR-307, ADR-308, ADR-309, ADR-311 and ADR-356; the `LLMCacheWriteLifetimeUnreported` runbook; the LLM pricing, providers, prompts, ReAct, database schema, Grafana, briefing, workboard and connectors documents; the FAQ and its knowledge corpus, the public presentations โ€” including two new animated cards on the *More* page โ€” settings search and the living maps, in six languages. - ๐Ÿงญ **The technical audit publishes its counter-review.** The V14 revision of 2026-10-22 re-examined every finding and score against the current code and lowers the published score from 8.0 to **7.8/10** (186.5/240) โ€” eleven areas down, usability up โ€” with 26 open findings (4 major, 11 moderate, 11 minor), 12 of them new (AC-028 to AC-039), and the closures it could prove (AC-024 and AC-025, AC-021 presumed; nine findings of V13). The public report, README, Story and How guides, FAQ, knowledge corpus and `llms.txt` carry it, with its prioritized remediation plan. - ๐Ÿ“ Public counters re-measured at the source: 66,000+ inventoried tests (52,397 backend tests collected across 3,500 files, 13,948 frontend tests across 1,118), 630 Prometheus metrics, 360 ADRs and 286 releases; the FAQ card of the Home page names its eleven cards again โ€” it still said nine. ## [3.4.0] - 2026-10-22 **LIA speaks first, your texts join in, places show the way.** Personal discussions LIA may open when you allow it, a private archive of the SMS your phone relays, place details and a priced route on the Position card, and scan protection shared by every API worker. ### Added - ๐Ÿ’ฌ **Proactive discussions** (ADR-358, ADR-359, ADR-360). Off until the person switches on *Allow LIA to start a discussion*, LIA may open a personal conversation of its own accord โ€” an interest in a plan, encouragement, an open question โ€” separate from notifications, which tell rather than invite a reply. The person sets the hours (across midnight if needed), a daily maximum, a pause, each allowed source, the sensitive topics and the topics to avoid; an opening offers four reactions (*Thanks, this resonates*, *Not now*, *Do not bring up this topic*, *This context is incorrect*). The derived context is visible: each element with its period and last reading can be allowed or not, deleted, purged or rebuilt, and the panel states the last rebuild, the last update and the last run โ€” why it ended, what it read and interpreted, what it cost โ€” with one plain sentence when a limit stops LIA. An archive, a logical opening and an outbox intent are published atomically, then delivered natively; human turns, approvals and alerts keep priority. Every model call and paid read is counted on the account under its quotas, within per-run, per-account-day and instance-day budgets; an opening informed by an SMS or a sensitive topic stays private (masked push, never an external channel), and each opening is an action of LIA's own initiative in the registers. The capability has its own switch; operator bounds are `DISCUSSION_*` settings. - ๐Ÿ“ฑ **Your SMS, relayed by your phone** (ADR-357). A write-only token per phone and an iPhone Shortcuts automation post each SMS to `POST /api/v1/ingest/message`; stable receipts tell stored, duplicate, conflict and invalid apart, item by item in a batch. **Settings โ€บ SMS** keeps an encrypted personal archive โ€” search, sender threads, names resolved from your contacts, erasure โ€” and recognised access secrets never reach storage. Assistant access is a separate consent, off by default; the chat, relationships, proactivity, the Radio and a phone call read bounded evidence under it. Immediate push stays content-free, the in-app notice names the sender, the Home card counts exactly and the personal export includes the readable SMS. Health ingestion keeps its contract. - ๐Ÿ—บ๏ธ **Place details and a route on the Position card** (ADR-355, ADR-356). Each place carries one number, the same in the list and on its pin. Selecting it shows the details the answer already gathered โ€” address, rating and reviews, phone, website, opening hours โ€” with no new search, and one route: walking up to 2 km, otherwise driving, corrected once when the actual walk is longer, from the browser position when it is already allowed, else the dated last known location, else home. Each paid call is filed once under the existing pricing and quotas, refusals and cancellations included; desktop popups and phone dialogs show the same facts. - ๐Ÿ“‡ **Address-book actions on a relationship card.** One button per email (*Email โ€ฆ*), postal address (*Directions to โ€ฆ*) and โ€” when the telephony connector is active โ€” number (*LIA call โ€ฆ*) prepares the request in the chat. On the contact card, an email opens the mail app, a whole number calls from the device and an address opens Google Maps. - ๐ŸŽซ **"My tickets" on the Home Workboard card** counts the tickets you hold; a ticket's last run keeps its cache and Google figures, and ticket costs show six decimals. - ๐Ÿงพ **The journal's last intervention** reads in the chat meter's vocabulary (IN, OUT, CACHE, GOOGLE, โ‚ฌ), cached tokens stored apart. ### Changed - ๐Ÿงญ **Alerts and Activity share one header**: *Activity timeline* or *Received / To follow up*, *Action journal* and *Refresh*, which re-reads the counts and every open section. Proactive discussions and *My SMS* join the Alerts hub. - ๐ŸŽจ **One neutral line** draws panel borders and separators on the signed-in screens (guarded), panels alternate their backgrounds, page headings carry a rule, and a line separates sections inside a panel โ€” never two panels. - ๐Ÿท๏ธ Shorter settings labels (*Proactive notifications*, *Memory*, *Limits admin*โ€ฆ); relationship rows are titled like an email โ€” how long ago and when โ€” and open on their direction, *Sent* or *Received*. - ๐Ÿค A capability shared with a connection is announced in the recipient's chat with the sender's name, and the share dialog confirms, warns or explains. - ๐Ÿ”„ SMS pages and health data refresh in place, without a visible reload. - ๐Ÿ“ฆ The personal export includes the proactive-discussion records (observations, states, runs, deliveries, forget markers), internal tokens removed. ### Security - ๐Ÿ›ก๏ธ **Scanners are banned across workers** (ADR-353). Distinct unknown-route 404s and rejected login or MFA credentials from one client earn a temporary ban held in Redis and shared by every API worker; ordinary resource and session errors never count. Internal callers, exact health probes and `OPTIONS` stay admissible, and a Redis failure lets traffic through while the metrics, the degradation alert and the diagnostics say so (`HTTP_SCAN_*`). - ๐Ÿงญ **Every HTTP 429 names its client** (ADR-354): one WARNING completion event carries the canonical client IP, method, query-free path, status and duration โ€” a retained log field, never a metric label. - ๐Ÿ” **Three dependency advisories closed as manifest floors** (ADR-331): certifi โ‰ฅ 2026.10.18 (GHSA-6q48-6c7w-9gw2, the distrusted emSign roots), langgraph-checkpoint-postgres 3.1.3 with langgraph-checkpoint 4.3.0 (GHSA-6hmw-9432-67qq, a dotted namespace label could reach another store namespace โ€” LIA's labels never carry a dot) and setuptools โ‰ฅ 84.1.0 in the wake-word toolbox (GHSA-xmj3-9gf7-h52w). ### Fixed - ๐Ÿ”’ **Handing a ticket to a connection no longer freezes the account.** Since v3.0.0 the assignment notice was sent inside the transaction that holds the account row, and the notice's own claim waited for it. Notices are now collected and dispatched after the commit through one door (AST guard), proven by a PostgreSQL lock-order test that fails on the old code. - ๐Ÿฉบ **The egress probe names the failing step and confirms a cut** (ADR-361): resolution then connection, paced attempts, a slow or recovered probe is degraded and never paged โ€” one lost DNS datagram no longer reads ยซ platform cut off ยป (`DIAGNOSTICS_EGRESS_PROBE_*`). - ๐Ÿงฏ **Every received alert records its incident again.** The open-incident upsert bound its partial-index predicate as a parameter, which a generic plan cannot match; the predicate is now one literal shared by model and repository. - ๐Ÿงฉ A skill shared by a connection installs on its first receipt (the recipient's state is flushed before registration hooks read it). - ๐Ÿงช ReAct validates tool arguments against their schema before running them; a deterministic provider 400 is no longer retried; too-short audio and a vendor 403 keep their permanent classification; numeric millisecond timestamps are no longer read as ISO dates; quoted JSON-schema instance data leaves no log above DEBUG; LLM callbacks name the model they know. - โฑ๏ธ Startup reports a successful cache load as such and audits the effective LLM slots, logging a refusal rather than failing every slot; Ollama discovery runs only when a slot needs it; a routine whose owner is unavailable settles without running; a timeout keeps its typed outcome. - ๐Ÿ™ˆ An inactive account sends no presence or profile-image request; a successful readability recovery and a valid medium-confidence routing log at their level. - ๐Ÿ  The Home SMS card shows previews only in a complete bundle, re-checked against an erasure. - ๐Ÿ”ค The journal search placeholder is translated in six languages (English only since v1.9.3), a misplaced SMS key no longer shows raw, and a disclosure's chevron follows its own block. - โŒจ๏ธ **Deleting a sender's or a day's SMS keeps the keyboard in place** (audit V14, AC-024): the erase button records where the focus returns for every scope, not only a single message, so once the refresh removes the group the focus lands on the archive's own disclosure โ€” never on a control the person chose meanwhile. - ๐Ÿ”Ž **Renamed administration panes stay findable by their full name** (audit V14, AC-025): the shortened titles (users, limits, usage export) keep their former names as search keywords in all six languages. ### Tests - ๐Ÿงช PostgreSQL proofs for the screen hand-over lock order, the open-incident upsert under a generic plan, the discussion context retention and the new migrations; the discussion tick, revalidation and reservations are covered under injected clocks and concurrency. - ๐Ÿ›ก๏ธ New guards: one assignment-notice door, the neutral line colour, refresh in place, i18n key placement; Playwright journeys for proactive discussions and their chat actions, the SMS archive, settings, Alerts, Home and relationships, and the Position details. - ๐ŸŽญ Browser journeys realigned on the interactions this release decided (audit V14, AC-021) without weakening their oracles: always-open Home rubriques, address-book actions beside the contact card, a share confirmed by its toast, two discussion-context panels, an SMS sender leading its words, call rows titled like mail, the badge measured by its pill; the Position layout is read in one frame. The fixtures now answer the connectors read a relationship makes. ### Documentation - ๐Ÿ“š ADR-353 to ADR-361, `PROACTIVE_DISCUSSIONS.md`, the SMS ingestion, qualification and iPhone Shortcuts guides, the FAQ and its knowledge corpus in six languages, public presentations, settings search and the living maps. - ๐Ÿ“ Public counters re-measured at the source: 1,003,000+ source lines, 58 backend domains, 66,000+ inventoried tests (52,293 backend, 13,919 frontend), 32 Grafana dashboards (847 panels), 327 catalogue tools, 93 model slots, 202 prompt files; the proactive sources are fourteen and the Home page holds eleven cards since the SMS joined them. The Story page description no longer quotes the test and ADR counts of an earlier release. - ๐Ÿงญ **Technical audit V14 published**: 8.0/10 over 24 normalized areas (192/240, security out of scope), its 16 worksites โ€” 3 major โ€” published with it. The public report, README, Story and How guides, FAQ and knowledge corpus carry it, and the history now lists V12 (8.3) and V13 (7.3), which had not reached the public surfaces. ## [3.3.0] - 2026-10-19 **Find, share and locate.** Full-text meeting-minutes search, independent capability copies between accepted connections, advisory source labels shared with the assistant, and a Position map before place details in every response format. ### Added - ๐Ÿ”Ž **Search meeting minutes before pagination.** Titles and complete current minutes participate in the same owner-scoped search as the result count. Accents and literal wildcard characters, cancelled requests and navigation back to the filtered list retain their tested behavior. No LLM call is added. - ๐Ÿค **Share skills, MCP servers and plugins with an accepted peer.** A reviewed, digest-bound package installs as an independently owned disabled copy, with sender/time provenance and native management. No credential, OAuth grant or approval exemption transfers. Durable claims, fencing, receipts and retention bound recovery and prevent retry from overwriting recipient changes. Enabled peer skills follow the explicitly accepted authored-policy exception; ordinary third-party imports retain isolation. See ADR-350 and the transfer guide. - ๐Ÿท๏ธ **Native advisory email and appointment labels.** Independent off-by-default JEV usages classify authorized visible evidence: email work/personal/spam/ phishing-scam and one normal/urgent/critical priority; appointment work/personal. Unknown stays unlabelled, normal priority stays quiet, and the assistant reads the same accepted annotations. Owner/account/evidence/policy/time-bound cache identities and bounded coalescence preserve quotas and actual cost accounting. The red phishing badge has a finite attention halo and static reduced motion. - ๐Ÿ—บ๏ธ **One Position card before selected native Google Places**, in Cards, HTML cards, HTML and Markdown. The card appears automatically; interactive Maps requires explicit cost-disclosed activation through the shared admission/SDK lifecycle. Missing coordinates/configuration and network failure retain usable source links; antimeridian and overlapping locations are covered. See ADR-352. - ๐Ÿ  **Optional interactive Maps in the installer.** Hidden browser-key and Cloud-map-ID questions may both be skipped. A complete env-safe pair enters only the private environment, never public state, logs or LLM bootstrap. Reconfiguration preserves operator values; bootstrap resumption does not ask for environment credentials again. Production rejects demonstration IDs. - ๐ŸŽฌ **Editable presentation-film sources and provenance.** The staged full-film scenes, deterministic timing tests, original recording receipts and offline score edit join the authoring tools. Preview packaging uses a configurable local origin; font and generated-music terms accompany the sources. No new paid media generation or runtime dependency is introduced. ### Fixed - ๐Ÿ”’ **Native MCP and plugin management keep their closed metadata contracts.** Sender/time badges remain visible in settings; their UI provenance is excluded from assistant reads and confirmation snapshots. Existing MCP management operations stay usable, without relaxing validation or forwarding private data. - ๐Ÿฉบ **CI PostgreSQL health probes use their declared database identity.** Readiness no longer creates misleading `role "root" does not exist` messages while reporting a healthy throwaway database. - ๐Ÿงฎ **JEV accepts feasible cent-rounded probability mass consistently.** The common native validator and annotation policy preserve raw weights and conservatively cap concentration, rather than rejecting the provider's approximate sum or increasing a winner to fill missing mass. Invalid schemas/options/winners/mass still fail atomically and retain known bills. - ๐Ÿง  **Semantic coverage is qualified separately from numerical validity.** Generic email questions distinguish reported severity from authentication, actual deceptive requests from security topics, and spam from unethical advertising. Fixed calibration, validation and post-freeze adversarial corpora pass without lowering confidence thresholds or changing expected answers. Critical holdout cases become displayable; no population-accuracy claim is made. - ๐Ÿ—บ๏ธ **Unavailable Maps no longer reserve a blank stage.** Explicit browser-key and Cloud-map-ID configuration replaces a hidden server-key fallback. Paid maps survive theme changes without reconstruction and cannot publish into a superseding account context. - ๐Ÿ“Š **Analyzer metrics retain the model captured with their operation**, even when an administrator changes the slot while later context work is running. - ๐Ÿ”‘ **An installation no longer presents someone else's OpenAI organization.** `openai_organization_id` defaulted to a constant named for another setting, and that constant had held the maintainer's real organization id since v1.29.0. The adapter sends the setting as the `organization` of every OpenAI client, and `.env.min.prod.example` โ€” the installer's template โ€” declares no `OPENAI_ORGANIZATION_ID`, so every installation the installer wrote presented that organization with its own key. The setting now defaults to empty (an organization is sent only when the operator sets one); `openweathermap_api_key` borrowed the same kind of constant and defaults to empty too. - ๐Ÿ“ฑ **An Android shell no longer receives someone else's Firebase project.** `firebase_project_id` defaulted to the maintainer's project: an operator who set the app id, the API key and the sender id but no project id published a mixed set to every Android shell. It defaults to empty, and the push configuration is offered only with all four values. The unread `telegram_bot_username` setting, which held the maintainer's bot, is gone (the bot's name is discovered at startup). ### Removed - ๐Ÿงน **The env settings of fourteen LLM slots, which nothing read** (ADR-244 amendment 2026-10-18 b): the voice comment and the thirteen domain agents resolve through `LLM_DEFAULTS` and the admin overrides. 126 settings fields, 98 constants (twelve still named `gpt-4.1-nano`, which retires on 2026-10-23), their ranges in `scripts/validate_config.py` and `scripts/validate_llm_config.py` โ€” a validator no command ran and which no longer imported โ€” are gone. Unknown variables are ignored, so a `.env` still carrying one keeps booting. - ๐Ÿงน **Fourteen more LLM env families, and the unread fields of two others**: the planner, the semantic validator and pivot, the three HITL slots, the memory, interest, heartbeat, broadcast and query-agent slots; `response` and `query_analyzer` keep their timeout alone. 97 constants, their validators and the LLM keys `scripts/validate_config.py` checked go with them. - ๐Ÿงพ **`scripts/validate_config.py` checks only keys something reads**: 27 more (`ENABLE_*_MIDDLEWARE`, `*CIRCUIT_BREAKER_ENABLED`, `RATE_LIMIT_CONTACTS_*`, `ROUTER_*`, `TOOL_APPROVAL_ENABLED`, `SEMANTIC_VALIDATION_ENABLED`...) named settings nothing declares. The env examples no longer document `ENABLE_FALLBACK_MIDDLEWARE=false` (the fallback chain is on) nor `LANGCHAIN_CALLBACKS_BACKGROUND` (LangChain 1.x reads nothing), and the degraded-mode runbook switches capabilities off instead of writing variables that change nothing. ### Tests - ๐Ÿงช Native fictional semantic evidence covers calibration, distinct validation and new multilingual adversarial observations, plus the actual service/Redis path. All historical and new attempts are reconciled with the real ledger. - ๐Ÿ›ก๏ธ The 23 registered JEV usages exercise single, batch and mixed Choice/Noul transport contracts under valid rounded and malformed responses: 138 tests, including quota admission, atomic publication and one retained bill. - ๐Ÿ›ก๏ธ `test_settings_default_family_guard.py`: a setting reads its default from a constant of its own family, or the pair is declared with its reason (shrink-only) โ€” the shape that let a production organization id become a default. ### Documentation - ๐Ÿ“š FAQ, release history, public presentations, relevant blog articles, settings search and FAQ-derived knowledge updated in six languages; living functional/technical maps and decision history include ADR-350โ€“352. JEV's qualification record retains failed candidates and the limits of its evidence. - ๐Ÿ”— Seventeen broken relative links in four dated plans now resolve; the ยซ effective production configuration ยป table of `GETTING_STARTED.md` names the models production runs (no slot runs `gpt-4.1-nano`), and the documents that described the removed settings point at the slot instead. `LLM_PROVIDERS.md` is rewritten around the one mechanism (code defaults + admin overrides) โ€” its examples were `.env` blocks for settings that configured nothing โ€” and the 2026-08-06 spec no longer quotes production identifiers. ## [3.2.0] - 2026-10-18 **A FAQ for every feature.** Ten new sections โ€” the home page, Telegram, calculations and scripts, habits, generated files and kept answers, the personal radio, LIA's psyche, the transparency registers, administration and self-hosting โ€” and the existing ones completed: 491 questions in six languages, where there were 375. **Voices that react, cues that fit.** On the radio, a chuckle, a laugh or a sigh may open a turn of a discussion or a debate, never the news read out. In a spoken comment a cue colours the news, never how LIA's own act went. A four-voice debate is no longer refused whole: it is split into takes the engine accepts. **A switch holds in both execution modes.** The tools a switched-off capability names leave the Pipeline planner and the ReAct loop alike, a delegated sub-agent and a skill's ready-made plan included โ€” the Workboard, LIA connections, MCP servers and Skills switches still close their pages alone โ€”; the bookmark, the avatar's mood and the voice's prosody follow their own switches. **An installation you can change, a supervision that tells the truth.** `./install.sh --reconfigure` changes a running installation without reinstalling it, and the Google Gemini key becomes an optional question. The daily report reads the alerts that fired, the latency alert measures only a person's wait, an incident whose resolution was lost closes itself, and a slot's output budget is held to what its model accepts. ### Added - ๐ŸŽ™๏ธ **The radio's voices react where a programme converses** ([ADR-324](docs/architecture/ADR-324-A-Personal-Radio-A-Grid-Decides-Models-Only-Write.md) decision 45): a chuckle, a laugh or a sigh may open a view or a transition of a discussion, a debate, the editorial, the opening or the sign-off โ€” never the news read out โ€” at most `RADIO_REACTIONS_MAX` (2) per programme, and only the sounds the station's voice performs. The editor silences one out of place and the line still airs. Measured on four model families (48 scripts): 11 discussions of 12 reacted at the story's turns, no bulletin ever did, and the editor silenced the four reactions written on a fact line. ElevenLabs v4 and Gemini 3.8 play the chuckle every time; Fish Audio's free model mostly as a short beat. - ๐Ÿ“Š **What the radio's voice cannot express is counted**: `radio_delivery_unrendered_total{dimension}` (energy, pace, tone, reaction), a new panel on dashboard 31. The segment already recorded it; nothing read it. - โ“ **The FAQ covers every feature you can use**: ten new sections โ€” the home page, Telegram, calculations and scripts, habits, generated files and kept answers, the personal radio, LIA's psyche, the transparency registers, administration and self-hosting โ€” and the existing ones completed, in six languages: 491 questions, against 375. The radio, among others, had no section at all. - ๐Ÿ”‘ **The installer asks for an optional Google Gemini key** ([ADR-215](docs/architecture/ADR-215-Self-Host-Installer.md) amendment 2026-10-18): memory recall, every search by meaning and image analysis run on it. An empty answer skips it, and the final report names every capability left waiting for a key. - โœจ **Two small-attentions cards with their animated scenes**: ยซ Voices that react ยป โ€” a commentator opens a reply with a chuckle, never a line of the news โ€” and ยซ The model's limit, in sight ยป โ€” a budget above the model's cap flagged before saving, each request held to it. The page holds 100 cards. ### Changed - ๐Ÿ—ฃ๏ธ **Each expression cue now says when it fits** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md) amendment 2026-10-17): the spoken comment's writer reads the meaning of every cue its voice performs, and keeps cues for the news โ€” never for how its own act went (a confirmation, a failure, nothing found). Measured over four model families (336 comments each way): cues where nothing called for one fell from 34 % to 25 % of the runs, cues that did not fit from 16 to 1, and the comments that call for a cue carry a fitting one 73 % of the time (53 % before). A comment that falls back to reading the answer, instead of the records it retained, now carries no cue at all, whatever its model writes. The example every cue-performing engine is shown is news (it was a confirmation of LIA's own act), and an engine that only pauses is no longer told about cues it cannot perform. - ๐ŸŽง **Each engine that performs cues gets the expressions its vendor documents**, re-read on 2026-10-17: ElevenLabs Multilingual v2, Flash and Turbo pause with their SSML ``; Gemini 3.8 hears a sentence's tone as that sentence's `style`; on every engine that plays it, ยซ concerned ยป is played as concern rather than empathy. Verified on the vendors themselves: across 67 transcribed clips no cue was ever read aloud. - ๐Ÿ“ฐ **The daily operations report reads what actually happened** ([ADR-119](docs/architecture/ADR-119-Alerting-Reactivation-Minimal-Core.md) amendment 2026-10-18): it opens on a ยซ Supervision LIA ยป section read from the systems that recorded the day โ€” the alerts Prometheus fired, the alert chain's own health, the alerts active now, the incidents still open, container restarts and recreations, memory peaks, probe failures โ€”, each source named when it cannot be read, never taken for silence โ€” and a window in which a source recorded nothing reads ยซ no measurement ยป, never ยซ nothing happened ยป. The tunnel section reads cloudflared's journal itself, counts each failed request once, by side (client gone, origin unreachable, other), groups an outage into its periods and reads traffic and HTTP codes from cloudflared's own counters; the Docker section presents itself as the dated snapshot it is. On production's report for 2026-10-17 the old sections read ยซ no restart, all stable ยป about a demonstrator API caught in a restart loop for six and a half hours, and counted 1,023 tunnel errors from log lines โ€” two per failed request, client cancellations included. - โฑ๏ธ **The time-to-first-token alert measures a person's wait** ([ADR-119](docs/architecture/ADR-119-Alerting-Reactivation-Minimal-Core.md) amendment 2026-10-18): routines, tickets and call relays stream through the chat code and fed the latency histograms, so three morning routines fired `SSELatencyP95High` every morning from 2026-09-19 on. Only a turn a person waits for is observed now โ€” one door, `streaming/latency_sli.py`, guarded by an AST test โ€” and the rule evaluates only over at least `ALERT_CORE_SSE_TTFT_MIN_OBSERVATIONS` (20) turns in ten minutes: below that, a histogram's p95 is its slowest single turn. - ๐Ÿ—ฃ๏ธ **The offline pages speak like the application**: the web offline page and the mobile shell's connection and offline screens address the reader in the familiar register in French, German and Chinese. ### Fixed - ๐Ÿ“… **The catalogue states Google's latest shutdown dates** (migration `754351d42c74`): the Gemini 3.1 Flash TTS, 2.5 Flash and Pro TTS, 3.1 Flash Live and 2.5 Flash native-audio (12-2025) previews retire on 2026-11-17, so the administrator is warned to move to the 3.8 models; `gemini-2.5-flash-image` runs until 2027-03-15, not the date already past it carried. - ๐ŸŽš๏ธ **A switched-off capability leaves both execution modes** ([ADR-280](docs/architecture/ADR-280-Complete-Capability-Control.md) amendment 2026-10-18): its tools were removed from what the Pipeline planner sees and nothing else, so the ReAct loop still bound them โ€” and the image and document tools, which read only the deployment flag, ran. The filter now applies once, to the turn's catalogue every reader shares โ€” a delegated sub-agent included, whose default research tools searched the web with web search switched off, and a skill's ready-made plan, which the validator and the executor resolved from the global registry โ€”; the image and document tools also refuse at their entry, and the administration panel says ยซ in both execution modes ยป. The router's domain menu reads the same snapshot, so a domain whose every tool a switch withheld is no longer detected; the planner offers delegation only when the turn does; and a skill's plan judges each step with the turn's own resolver, never a stricter name match. The Workboard, LIA connections, MCP servers and Skills switches still close their pages alone, and the FAQ now says so. Reading the switches on every turn costs one cache read and at most one query: a switch nobody ever wrote is cached as absent instead of reaching the database each time. - ๐Ÿ”– **The bookmark follows the Bookmarks switch** ([ADR-282](docs/architecture/ADR-282-Message-Bookmarks.md) amendment 2026-10-18): switched off, the bubble kept offering a bookmark whose every click was refused. It now offers to keep nothing new, while an answer already kept keeps its mark and can be let go; what was kept stays readable, downloadable and deletable. The web reads every capability's effective state through one rule (`lib/capability-state.ts`). - ๐Ÿ™‚ **ยซ Show emotional avatar ยป off returns every answer's face to neutral**: the switch only stopped the live mood, so every finished answer kept showing the mood stored with it. - ๐ŸŽ™๏ธ **The mood bends the voice only where the psyche is on** ([ADR-237](docs/architecture/ADR-237-voice-prosody-and-form.md) amendment 2026-10-18): the direct readout followed a mood frozen when the person switched the psyche off, and one who switched it off before any state existed was given one by their first readout (a spoken comment never bends the voice). - ๐Ÿ” **Searches by meaning read the Gemini key set in LLM Configuration** ([ADR-069](docs/architecture/ADR-069-Gemini-Embedding-Migration.md) amendment 2026-10-18): memory recall, knowledge spaces, journals and interests read `GOOGLE_GEMINI_API_KEY` (else `GOOGLE_API_KEY`) from the environment, once. The administration key is now read first, at every call, so a key added there needs no restart โ€” except for the tool ranking and the tool-context store's index, both built at boot. - ๐Ÿ› ๏ธ **`./install.sh --reconfigure` changes a running installation without reinstalling it** ([ADR-215](docs/architecture/ADR-215-Self-Host-Installer.md) amendment 2026-10-18): it fell through to a fresh install โ€” every question asked again, the `.env` re-rendered from the template, the seeds re-armed, the images rebuilt, the typed provider keys replacing the stored ones. It now asks the routing and capability questions showing the answers in force, which Enter keeps; replaces each validated file in one atomic step after a private backup; recreates the containers without rebuilding; makes Caddy reread changed routes and stops the services of an option turned off; rewrites only the `.env` values the answers decide โ€” every value it would change shown first, nothing applied until confirmed โ€”; and, if the new stack does not come back ready or is interrupted (Ctrl-C, SIGTERM, SIGHUP, at any step of the swap), puts the previous files and stack back and checks them ready, logging the cause first and, should the restore itself fail, printing the exact Compose commands. Turning the sandbox on writes `DOCKER_GID` from the Docker socket's group. Moving a LAN install behind Caddy, impossible before, works. - ๐Ÿ“‹ **The installer's final report names what stays degraded**: it was handed a hard-coded empty list. The bootstrap reports the capabilities left waiting for a key โ€” from the keys the database holds, so a `--resume` that skips the optional key no longer reports a stored one missing โ€” and the installer keeps that list for a later `--resume`. - ๐Ÿงญ **Nine messages named settings that moved**: the image-generation, health-data and two skill refusals, the two remote-dictation errors, the administrator's voice listing, the unserved image model and the voice-mode API description now point at the current place. - ๐ŸŒ **Labels left in English are translated**: the reasoning fields of the administration's model dialog and the ยซ other ยป slice of the register charts, in six languages. - ๐Ÿ€„ **Chinese labels say what they mean**: the radio's brief (็ฎ€่ฎฏ) and news flash (ๆ’ๆ’ญๅฟซ่ฎฏ) no longer share one word; the columnist, the commentators and the automatic stop are named precisely; the workboard has one name (ๅทฅไฝœ็œ‹ๆฟ, where three alternated), ยซ register ยป one word across the application (็™ป่ฎฐ็ฐฟ), the psyche keeps one word for the mood (ๆƒ…็ปช) and one for the emotions (ๆƒ…ๆ„Ÿ), its tooltip included, and LIA's journals are ๆ—ฅ่ฎฐ, never a log (ๆ—ฅๅฟ—). - ๐Ÿ‡ฉ๐Ÿ‡ช **German settings paths no longer read ยซ Einstellungen โ€บ Einstellungen ยป**: the Preferences tab is ยซ Prรคferenzen ยป, and the FAQ paths name it โ€” and the Konnektoren, Besprechungen and Verwaltung labels the German screens show. - ๐Ÿ“ **The FAQ names the screens as they are**, in six languages: ยซ LIA's journal ยป and ยซ System RAG admin ยป instead of names they never had, and the workboard reached from My shortcuts or its settings section โ€” it has no header entry. - ๐Ÿ“ **A slot's output budget is held to what its model accepts** ([ADR-244](docs/architecture/ADR-244-LLM-Catalogue-Truth.md) amendment 2026-10-18): three production slots kept the 200,000-token budget chosen for their previous model when they moved to one whose output is capped at 128,000, and the provider refused every call โ€” document generation failed. One rule (`infrastructure/llm/output_cap.py`) holds a slot's `max_tokens` to the output cap a vouched catalogue row declares โ€” `imported` or `verified`, on a provider that enforces one, the column default only where a vendored registry states that very figure โ€” read by the slot resolution, the client door and the admin metadata; in doubt the request goes as configured. The LLM configuration screen flags a slot whose budget exceeds its model's cap โ€” a badge on its card, a warning under the field while it is edited โ€” and saving is never refused: the stored figure stays the administrator's to correct. - ๐Ÿ’“ **A stray source label no longer costs a whole heartbeat decision** ([ADR-135](docs/architecture/ADR-135-Heartbeat-Interest-Quality.md) amendment 2026-10-18): one word outside the source vocabulary rejected the entire decision on every structured-output path, and production lost three heartbeat ticks of five for one account once its decision slot ran a model with reasoning on. Case, spaces and hyphens are now repaired and a word naming no source is dropped and counted in a log (`heartbeat_source_labels_dropped`); the published schema is unchanged byte for byte and only canonical labels are stored. - ๐Ÿฆ™ **An unreachable Ollama address no longer slows every admin save** ([ADR-267](docs/architecture/ADR-267-Ollama-Native-Provider-And-Discovered-Capabilities.md) amendment 2026-10-18): while a configured server stayed off, every configuration reload โ€” each save of any slot, each cross-worker invalidation โ€” waited the five-second discovery timeout (production: 16 timeouts in 17 minutes). An address that answered nothing is asked again at most once per `OLLAMA_DISCOVERY_RETRY_SECONDS` (600; `0` keeps the former behaviour); a changed address is still discovered at once, and the admin's model listing still asks the server. - ๐ŸŽ™๏ธ **A radio debate keeps its takes** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md) amendment 2026-10-18): the anchor and three commentators were planned as one take of four voices, which Fish Audio refuses whole (ยซ Reference audio too long ยป), so the segment fell back to line-by-line synthesis. Each engine family declares how many voices a dialogue take holds (`TtsFamily.dialogue_max_voices`: three on Fish, measured 10 of 10 accepted at three and 5 of 5 refused at four) and the planner opens a new take where one more voice would pass it; over 20,000 seeded scripts the plan is unchanged wherever no take passed the limit. - ๐Ÿงพ **An incident whose resolution was lost closes itself** ([DIAGNOSTICS_DOMAIN](docs/technical/DIAGNOSTICS_DOMAIN.md)): an alert incident stayed open as long as its ยซ resolved ยป delivery was missing โ€” one for 28 days. Each self-check tick now closes an alert incident Alertmanager no longer holds as firing and that has had no news for `DIAGNOSTICS_INCIDENT_SILENCE_CLOSE_SECONDS` (an hour by default), with an audit entry; a silenced or inhibited alert counts as active, an unreachable Alertmanager closes nothing โ€” nor one restarted less than five minutes ago, which lists nothing until Prometheus re-sends what is firing โ€”, and Alertmanager is read outside the database transaction. The audit append itself, refused by PostgreSQL, had never run and now does. A malformed telemetry URL is now an unavailable source, no longer an exception that ended the whole tick, and the diagnosis pump waits on Prometheus, Loki and the model with no transaction open (ADR-304). - ๐Ÿš€ **The production deploy no longer stops before building**: the new logwatch tests wrote a `__pycache__` beside the extensionless scripts, the deploy bundle copied it, and `deploy.sh`'s `cp services/*` under `set -e` exited at step 4/7. The loaders write no bytecode, the bundle drops bytecode, and the deploy copies regular files only โ€” each layer pinned by a test. - ๐Ÿงฎ **A pricing workbook exported in German, Spanish or Italian imports back**: the reader refused the WAHR/FALSCH, VERDADERO and VERO its own writer wrote. One declaration now serves both, round-trip tested in the six languages. - ๐Ÿฆ™ **An Ollama slot's own context window reaches the server** ([ADR-278](docs/architecture/ADR-278-Per-Slot-Context-Window.md)): the factory handed the adapter a key its merged configuration never held, so `num_ctx` fell back to the discovered window while the compaction threshold and the ReAct budget read the slot's own figure โ€” what LIA accounted with was not what it requested. - ๐Ÿ” **A rollback no longer reads every untouched capability as off**: a switch nobody ever wrote is cached as an absence under a key family the previous release never reads (`system:capability:v2:`); read by v3.1.1, the marker decoded as ยซ off ยป until its five-minute expiry. - ๐ŸŽค **The Live voice sample outlives the 2.5 TTS shutdown**: it now speaks through the one Gemini TTS client, on the person's own key, and defaults to `gemini-3.8-flash-tts`; the deprecated-model guard also holds the sample, Live, embedding, search and diarisation defaults. A deployment that pins `LIVE_VOICE_SAMPLE_MODEL` keeps its own model. - ๐Ÿงฉ **A plugin's skill says where it is managed**: its refusal sent the model to the Skills section; it now names the Plugins section, from which such a skill leaves with its plugin. ### Security - ๐Ÿ”’ **`re2js` 2.8.8** through a pnpm override (GHSA-gg6h-894w-4m9c, high: quadratic-time lookbehind matching), found by the dependency watch โ€” reached only through `firebase` โ†’ `@firebase/firestore`, which LIA never imports. - ๐Ÿ”’ **`filelock` 4.2.2** under a security floor in the wake-word toolbox's two manifests (GHSA-v4x8-3wr5-3wq8, high, and thirteen more advisories), pulled by torch and the Hugging Face stack; the toolbox never reaches production. One more Pillow 12.3.0 advisory there (GHSA-5x8w-8jj5-q52h, FlashPix) is accepted on the same condition as the twenty-one before it: gradio still caps Pillow below 13, and the toolbox decodes no image. ### Tests - ๐Ÿงช `test_turn_catalogue_single_authority_guard.py` (AST) keeps one builder of the turn's catalogue: the snapshot every reader shares is set from `build_turn_catalogue` alone, and the unfiltered base is built nowhere else. - ๐Ÿงช The FAQ section registry guard holds the six locales' sections, the display order and the icons equal โ€” a section translated in six languages but absent from the order rendered nowhere, with no test red. - ๐Ÿงช The latency door is AST-guarded: nothing but `latency_sli.py` observes the two latency histograms (time to first token, stream duration), and the alert rule's negative case (a routine morning) is pinned in `promtool` tests. - ๐Ÿงช The incident reconciliation runs on a disposable PostgreSQL (four cases, the audit append included), and its silence window is held to at least twice the webhook's repeat interval. - ๐Ÿงช **The agents suite no longer hangs**: its voice fake refused the spoken comment's new `speaks_of_records` keyword, so one sequence failed and another waited forever โ€” the CI step would have run until GitHub's six-hour limit. The fake records the value, the harness waits at most five seconds, and it now drives the real batch read of the switches. - ๐Ÿงช New pins: the pricing workbook's true/false words over six languages, the router's domain menu under switches, the skill plan's canonical resolution, the planner's delegation section, the radio's reaction cues (boot-checked complete), the Live sample through real ffmpeg, logwatch loaders that write no bytecode and the deploy copy that skips directories. - ๐Ÿงช The output cap is tested at its three readers, the heartbeat labels on every structured-output path, the dialogue takes over 20,000 seeded scripts, the installer's reconfiguration from interruption to restoration, and the bookmark, avatar and prosody gates on and off. ### Documentation - ๐Ÿ“š **The decisions follow the code**: amendments to ADR-069, ADR-119, ADR-135, ADR-215, ADR-237, ADR-244, ADR-267, ADR-280, ADR-282 and ADR-345 (two), ADR-324 decision 45, each mirrored in the ADR index; DIAGNOSTICS_DOMAIN, LLM_CONFIG_ADMIN, RADIO, VOICE, LOCAL_EMBEDDINGS, METRICS_REFERENCE, GRAFANA_DASHBOARDS, the self-hosting and observability guides, GETTING_STARTED and three alert runbooks say what the code now does; `CLAUDE.md` gains three rules (a slot's output cap, the turn's catalogue filtered once, the latency SLI's single door). - ๐ŸŒ **The public surfaces**: the README; in six languages, the How, philosophy and story guides (the turn's catalogue, the output cap, cues by meaning, the radio's reactions and takes, the latency SLI and the daily report, incident reconciliation, `--reconfigure`); the ยซ How LIA works ยป cards, rebalanced under their shrink-only length caps; the landing's radio and voice cards; three blog articles (observability, LLM configuration governance, voice mode); the FAQ answers and the help corpus, checked against the code; the settings search lexicon; three bricks of the living maps. - ๐ŸŒ **The six languages reviewed key by key**: UI labels quoted as the screens show them, the familiar register restored outside the legal pages (French, German, Spanish, Chinese), examples without dialable numbers, configurable values stated as defaults, the help corpus aligned with the English FAQ, and LIA's journals called ๆ—ฅ่ฎฐ in Chinese. - ๐Ÿ”ข **Figures that had drifted are corrected or let go**: the How guide and the observability article counted 29 vital alerts where the core holds 31, and the ยซ How LIA works ยป card 27 capabilities where the registry holds 34 โ€” both figures leave the prose, which a guard cannot hold; the governance article counted 86 LLM configurations instead of 87. - ๐Ÿ“œ **GitHub recognises the AGPL-3.0 license**: `LICENSE` is now the verbatim text published by gnu.org โ€” the header line placed above it kept GitHub from detecting the license โ€” and the copyright line moves to the README's License section. `SECURITY.md` 1.2 names no release line in its supported versions and lists the code scanning CI actually runs (CodeQL). ## [3.1.1] - 2026-10-17 **On a phone, LIA's companion stays where you put it.** The eyes no longer step away from buttons and headings or fold into a dot on their own on a small screen: you drag them, or minimize them to their restore dot, and they stay there whatever the page does underneath. On the radio, the station's music sits lower under every voice. The image library moves to Pillow 13.0.0, which closes twenty-one advisories published the day before. ### Added - ๐ŸŽต **ยซ The music makes way ยป**, a small-attentions card with its own animated scene: a voice row and a music row, the music dipping fast before the first word and rising slowly after the last. ### Changed - ๐Ÿ“ฑ **On a phone, you alone place the companion** ([ADR-240](docs/architecture/ADR-240-expressive-eyes-widget.md) amendment): below 1024 px the widget runs no avoidance and has no compact mode. The v3.1.0 placement re-solved its spot against every control and heading on each scroll, so it jumped while you scrolled, and it stayed a dot on every page but the chat. A drag, the arrow keys or the minimize button are now the only things that move or fold it; on a wide screen only the default spot โ€” never one you chose โ€” still steps off a control. The placement helper drops the panned-viewport offset that only the phone path read. - ๐Ÿ“ป **The radio's music steps back under the voices** ([ADR-324](docs/architecture/ADR-324-A-Personal-Radio-A-Grid-Decides-Models-Only-Write.md)): the music bed goes down to about โˆ’16.5 dB under every programme (โˆ’12 dB before), still in 0.35 s before the first word and back up in 1.2 s after the last. ### Removed - ๐Ÿงน The ยซ The companion makes room ยป card and its animated scene leave the small-attentions page, which keeps its 98 cards in six moments. ### Security - ๐Ÿ”’ **Pillow 13.0.0** (security floor `Pillow>=13.0.0` in the API and sandbox manifests): twenty-one advisories from Pillow's own repository, one critical (GHSA-v9pv-5gc8-w2m6, multi-frame loaders reusing stale native storage) and nine high (JPEG and TIFF heap overflows, decompression-bomb bypasses). LIA decodes images a stranger can send โ€” uploads, mail attachments, image edits โ€” so the floor moves the runtime, dev and sandbox locks together; no API the code uses was removed, and `pillow-heif` and `python-pptx` accept the new line. The wake-word GPU toolbox alone keeps 12.3.0, because `gradio` (required by VoxCPM) caps Pillow below 13: it decodes no image and never reaches production, and each advisory is accepted there with that reason until `gradio` lifts its cap. ### Tests - ๐Ÿงช The widget tests pin a phone where nothing moves the companion: a saved spot and the default corner stay unchanged, face whole, under a heading, a control, a scroll and a resize. The mobile settings smoke checks that the companion keeps its spot across scrolling while the search restores the settings rail, and the avoidance hook's tests keep the wide-screen default only. - ๐Ÿงช Every authenticated end-to-end journey on a phone starts with the companion minimized and its dot moved aside, unless the spec stored a companion preference of its own (every companion spec does) โ€” what a person reading and tapping would have done; at its default corner it covered a control in ten journeys. One helper file (`e2e/fixtures/companion.ts`) holds it, and the meetings and notifications fixtures reuse its `minimizeCompanion`. - ๐Ÿงช The notifications layout checks read every box they compare in one frame and wait for the layout to settle: two separate reads could straddle a reflow, and the spec had gone flaky at 320, 390 and 1440 px for that alone. - ๐Ÿงฐ `task test:e2e` blanks the telemetry and showroom build flags a developer `.env` sets, as CI does: baked on, telemetry posted `/product/events` from every page past the network guard and failed four settings journeys locally. ### Documentation - ๐Ÿ“š ADR-240 records the 2026-10-17 decision, mirrored in the ADR index and in `docs/ARCHITECTURE.md`; ADR-324 states the new music level. The FAQ answer on LIA's eyes, the ยซ How LIA works ยป radio card and the landing's radio card, the how and why guides, three blog articles (voice mode, security architecture, psyche engine), the help corpus and the functional map's radio brick say the same in the six languages. ## [3.1.0] - 2026-10-17 **Your mailbox drafts, managed from the conversation.** LIA now keeps drafts in your own Gmail, Outlook or iCloud mailbox: it saves a new one, prepares a reply or a forward as a draft, lists them, edits them and moves them to the trash without asking, because nothing reaches anyone. Sending a draft is the one act that asks first, on a card showing the draft as your mailbox holds it. **A fifth voice, Fish Audio, and voices that perform.** Fish Audio joins the speech engines: five synthesis models, transcription for the voice mode and the meetings, and a voice library administrators clone and design into. A sentence heard is billed once, by the engine that spoke it; LIA writes a few expressive cues where an engine performs them, and the radio voices its exchanges in one take. **An assistant that learns where it is reliable โ€” from evidence, never from its own grade.** LIA keeps a private experience per domain on two axes that are never merged: what a turn verifiably achieved, and what you found useful. Where the evidence is thin it checks once, asks one question or names what it could not verify; its own mood score no longer passes for competence. **A home page, settings and lists redrawn for reading.** Today opens on the date and LIA's living face; meetings and calls read as timelines; LIA's psyche is drawn; panels alternate their depth, a button keeps its label while it waits, documents show their first page, and an error is never shown as an empty list. ### Added - ๐Ÿ“ฎ **Mailbox drafts** ([ADR-344](docs/architecture/ADR-344-Mailbox-Drafts-Kept-Freely-Sent-After-One-Confirmation.md)): six tools over one client contract shared by Gmail, Outlook and iCloud โ€” list (filtered by recipient, subject or words, limited to the number asked), create, prepare a reply (written by LIA from the received e-mail when you dictate nothing) or a forward, edit (by value or by instruction, the quoted message kept), and trash one, several or all of them, at most `EMAIL_DRAFTS_BULK_MAX` per call with what remains stated. - ๐Ÿ“ค **Sending a draft asks once:** the card shows the draft as the mailbox holds it; a draft edited in the mailbox since is not sent, and a change asked on the card is written to the draft before it leaves. Several drafts are confirmed as one lot. - ๐ŸŸ **Fish Audio speaks** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md)): `s2.1-pro`, `s2.1-pro-free`, `s2-pro`, `s1` and `drama-3` on the voice and radio slots, billed per UTF-8 byte of the text, with output format, latency, speed and transport (HTTP or the real-time WebSocket, whose session is answered over HTTP when it falls silent) tuning; `s1` carries the retirement its vendor announced. The picker offers the account's own voices, the vendor's licensed ones and the public voices an administrator pinned after attesting the right to use them. - ๐ŸŽ™๏ธ **Fish Audio transcribes:** `transcribe-1` and `transcribe-1-pro` serve the voice mode's remote dictation and the meetings, speakers separated; a recording longer than one request takes moves to the next engine before it is uploaded. - ๐Ÿงฌ **A voice library for administrators** (Settings โ€บ Administration โ€บ Voice library): clone a voice from recordings under a consent attestation filed in the audit log before anything leaves, design one from a description โ€” a flat price (`FISHAUDIO_VOICE_DESIGN_COST_USD`) charged to the instance's daily budget โ€”, rename or delete them; a voice a slot speaks with is never deleted. `FISHAUDIO_VOICE_CREATION_ENABLED` switches creation off (off on the demonstrator). - ๐ŸŽญ **Expressive cues where an engine performs them:** the spoken comment carries a few (a sigh, a laugh, a whisper) under one budget (`VOICE_EXPRESSIVE_CUES_MAX`) and each radio line one from its tone, written in each engine's own syntax โ€” ElevenLabs v3 and v4, Fish Audio's S2 models, `s1`, `drama-3`, Gemini. - ๐ŸŽง **The radio voices a dialogue in one take** on the engines that voice several speakers: each turn is placed by the vendor's timestamped stream, and a take that cannot be placed is voiced line by line. - ๐Ÿ—ฃ๏ธ **LIA's voices are yours to choose** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md), amendment 2026-10-14): in Settings โ€บ Voice mode, pick LIA's male and female voice among the voices of the engine that speaks in the chat, each list opening on the administrator's voice. The choice is kept per provider โ€” a model change keeps it, a provider switched back to finds it โ€” and applies to the voice comments and to what LIA reads aloud; the radio, live sessions and phone calls keep their own voices. It is part of your account's export, and erased with your account. - ๐ŸŒ **The voices of your language, at a switch:** every voice picker โ€” the administrator's voice slots, the radio's roles, LIA's voices โ€” offers ยซ only voices in my language, and multilingual ones ยป, on by default, never hiding a voice already chosen. - ๐Ÿ”Š **Hear a voice before you keep it:** choosing a voice for LIA or for one of the radio's roles plays a short sample of it at once, in your language, with one control to stop it or play it again; a newer choice cancels the previous sample, a radio that is playing pauses, and a meeting recording or a Live session keeps priority. Two doors serve it (`POST /voice/lia-voices/sample`, `POST /radio/voices/sample`): authenticated, capability-gated and rate-limited, they take no free text from the browser and bill the sample like any reading โ€” the radio's budget counts it too. - ๐Ÿ“Š **Every failed step of a pipeline plan is counted under its typed code** ([ADR-346](docs/architecture/ADR-346-Advisory-Replanner-Retired-A-Pipeline-Failure-Is-Said-Never-Replayed.md)): `pipeline_step_failures_total{error_code}`, dashboard 07 ยซ Pipeline Step Failures ยป โ€” a failure that happens before a tool is called, such as a reference to an earlier step that could not be resolved, included: no tool metric and no register saw it. - ๐ŸŽ™๏ธ **The radio's commentators speak with the voices you choose** ([ADR-324](docs/architecture/ADR-324-A-Personal-Radio-A-Grid-Decides-Models-Only-Write.md) decision 43): the three commentators of debates and discussions get a voice each in the radio settings, automatic by default as before. A commentator never shares a voice with LIA, the anchor or another commentator: the settings grey those voices out and a save refuses them (`radio_voice_shared`). - ๐Ÿงญ **What a read tool finds reaches the answer** ([ADR-347](docs/architecture/ADR-347-Read-Tool-Data-Reaches-The-Pipeline-Answer-A-Declared-Failure-Is-Never-A-Success.md)): in the default mode the answer was written from a sentence about the data โ€” ยซ 2 destinations ยป โ€” while the travel times, the connections or the next page of a search sat beside it unread. The data now reaches it as in the autonomous mode: everything the cards do not already show, wrapped as third-party content, within a budget, every cut stated. Measured before: 0 of 9 answers gave the travel times, 27 of 27 with the data. - ๐Ÿงญ **LIA learns where it is reliable, from evidence** ([ADR-348](docs/architecture/ADR-348-Efficacy-Learned-From-Evidence-Results-And-Usefulness-Kept-Apart.md)): seven domains โ€” planning, information, emotional support, creativity, technical, social, organization โ€” keep a private experience on two axes never merged: what a turn verifiably achieved (the final coverage of the requested outcomes, never an HTTP status) and the usefulness you expressed (๐Ÿ‘/๐Ÿ‘Ž on the final answer). An index exists only from five observations within ninety days. With that evidence, LIA may verify a point the turn left open, ask one clarifying question or name what it could not check โ€” in the pipeline, the autonomous mode and the answer alike โ€” and changes no model, permission, budget or confirmation. Settings โ€บ LIA's psyche shows ยซ No index yet ยป, ยซ Learning ยป or ยซ Observed ยป with each axis' basis; the evidence is exported with your account and erased by a full psyche reset or a purge. `PSYCHE_EFFICACY_COLLECTION_ENABLED` and `PSYCHE_EFFICACY_INFLUENCE_ENABLED` switch each half off. A pilot: no gain is claimed before a held-out comparison. - ๐Ÿ”Š **Gemini voices the chat too** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md)): a chat voice slot set to Gemini used to speak through Edge, because the chat could not record a token-billed voice; every speaking surface now records through one door, so the chat speaks with the voice configured. - ๐Ÿ  **A home page that opens on your day:** the date is the page title and rolls over at midnight in your time zone; a compact welcome card carries LIA's live face, a one-click switch to the other avatar, the greeting and its cost; the radio, your shortcuts and ยซ My dashboard ยป follow, and they still render when the briefing fails. LIA's briefing can be folded, listened to and cancelled while its voice loads, and says when a refresh failed. The agenda groups events by day on a timeline, each one an interval with its time-zone offset when a clock change falls inside; birthdays say the age, documents their type, the weather draws its sky, health colours its figures, and the workboard card counts the tickets held with your connections and previews the first two of each count. Consumption is one table, with input, output and cached tokens and the Google API requests. - ๐Ÿ—“๏ธ **Meetings and calls read as timelines:** grouped by local day and by period (night, morning, midday, afternoon, evening), with start and end times โ€” an end is never guessed from a duration โ€” and, for meetings, how the format was chosen, the indexing state and the engine that transcribed it. - ๐Ÿ”” **The alerts hub in two groups:** ยซ Upcoming and to follow up ยป and ยซ Already received ยป, proposals answered by two visible buttons, full texts, and readable source names in the histories. - ๐Ÿง  **LIA's psyche, drawn:** emotion rings around the mood, a pleasure ร— arousal plane, the personality's Big Five pentagon, ring meters for the relationship, the drives, the new experience panel and an evolution chart on a true time axis โ€” every instrument a labelled meter. - ๐Ÿ‘๏ธ **A preview before you choose a display mode:** Settings โ€บ Display mode draws a sample answer in each format, and each mode says in one line what sets it apart โ€” ยซ Cards ยป keeps a classic paragraph beside the cards, ยซ HTML + cards ยป composes a synthesis with a title and a takeaway around the same cards. - ๐Ÿ“„ **Generated documents show their first page:** in the gallery, a PDF shows its real first page and a text or Office file an excerpt labelled as such, loaded only when the card nears the screen. ### Changed - ๐Ÿ”‡ **The radio's second-model verification is off by default:** a listener who never chose gets no model check (`RADIO_VERIFICATION_DEFAULT=off`), since each check is billed and can delay the listening; ยซ Verify the news ยป and ยซ Verify everything ยป stay one choice away in the radio settings. - ๐Ÿ’ถ **A sentence heard is billed once, by the engine that spoke it:** every speaking surface goes through one synthesis door and is recorded in that engine's own unit โ€” characters, UTF-8 bytes, or the tokens a vendor reports. - ๐Ÿšฆ **One request allowance per vendor account:** Fish Audio has its own (`FISHAUDIO_MAX_CONCURRENCY`) beside ElevenLabs', on one seam shared by every worker; every Fish Audio request โ€” synthesis, transcription, voice design, the voice listing โ€” takes a slot, so a request past the account's limit waits its turn within its own bound instead of meeting the vendor's refusal. - ๐Ÿ“Œ **The pinned public Fish Audio voices are shared:** one list for the chat's and the radio's voice slots, the slots' former pins merged into it, under a ceiling the operator sets (`FISHAUDIO_PINNED_VOICES_MAX`). Pinning and unpinning take effect at once, the attestation is filed in the audit log before a pin is stored, and a voice a slot speaks with cannot be unpinned. - โฑ๏ธ **The ElevenLabs voices offered in the voice mode and radio settings are read from a ten-minute cache,** so a voice turn never waits on the vendor's listing; the administration's picker still reads the account live. - ๐Ÿง  **LIA's self-rating no longer counts as competence** ([ADR-348](docs/architecture/ADR-348-Efficacy-Learned-From-Evidence-Results-And-Usefulness-Kept-Apart.md), [ADR-068](docs/architecture/ADR-068-Psyche-Engine.md) amendment 2026-10-16 b): the old self-efficacy score, fed by LIA's own rating of a conversation into ยซ emotional support ยป, and the caution it injected on ยซ weak domains ยป are retired; the self-report keeps feeding the mood, the emotions and the relationship. Old scores stay readable and are not converted. `PSYCHE_SELF_EFFICACY_PRIOR_WEIGHT` has no effect any more. - ๐ŸŽ™๏ธ **The remote dictation cap names no vendor:** `ELEVENLABS_STT_MAX_AUDIO_DURATION_SECONDS` becomes `REMOTE_STT_MAX_AUDIO_DURATION_SECONDS` (the old name is still read), and `FISHAUDIO_STT_ENABLED` switches Fish Audio transcription off like its ElevenLabs sibling. - ๐ŸŽง **Dialogue takes are bounded and counted:** `RADIO_DIALOGUE_MAX_BYTES` (`0` voices every line alone) and `radio_dialogue_takes_total` (dashboard 31); a Fish Audio socket answered over HTTP is counted by `voice_tts_transport_fallbacks_total` (dashboard 11). - โธ๏ธ **A personal MCP server that fails to connect is paused** ([ADR-224](docs/architecture/ADR-224-Conformite-MCP-2026-07-28-SDK-v2.md), amendment 2026-10-13): it used to be retried at every turn, each attempt up to its timeout. The pause starts at `MCP_USER_FAILURE_PAUSE_BASE_SECONDS`, doubles up to `MCP_USER_FAILURE_PAUSE_MAX_SECONDS` and is shared by every worker; a success, an edit or a re-authorisation lifts it, and the manual test ignores it. - ๐Ÿ—œ๏ธ **A compacted conversation keeps its identifiers** ([ADR-086](docs/architecture/ADR-086-Conversation-History-Compaction-v2.md), amendment 2026-10-13): an id, a URL or an address the summary dropped is written back under it, marked untrusted when it came from third-party content, up to `COMPACTION_IDENTIFIERS_REINSERT_MAX` per list. - ๐Ÿงฉ **The step limits of the expert, browser and MCP loops count graph steps** ([ADR-083](docs/architecture/ADR-083-Sub-Agent-Delegation-React.md), amendment 2026-10-13 b): N steps buy Nรท2 model calls, the last one writing the answer. The lowest accepted values rise โ€” `SUBAGENT_DEFAULT_MAX_ITERATIONS` โ‰ฅ 2, `BROWSER_REACT_MAX_ITERATIONS` and `MCP_REACT_MAX_ITERATIONS` โ‰ฅ 4 โ€”, and a `.env` below them now refuses to start. - ๐Ÿ” **Mail servers must present a valid certificate:** LIA's own SMTP relay and iCloud's SMTP and IMAP verify the certificate and the host name before logging in, where `STARTTLS` used to accept any certificate. A relay with a self-signed certificate must be given a trusted one, or the verification and notification e-mails will not leave. - ๐ŸŒ **Browser sessions are admitted atomically** ([ADR-059](docs/architecture/ADR-059-Browser-Control.md), amendment 2026-10-15): one Redis registry with per-entry expiry (Redis 7.4, as Compose and the installer ship), so a stale worker can no longer overwrite a newer context and every worker cleans its own idle ones. - ๐ŸŽจ **Panels read their depth:** a panel inside a panel takes the darker tone, then the lighter one again, in light, dark and absolute black alike, and a field takes the opposite tone of the panel it sits in. - โณ **A button keeps its label while it waits:** it shows a small spinner, keeps its size and its focus, and ignores a second press; pagination, toolbars and row actions follow the same rule. - โš™๏ธ **Settings, tidied:** absolute black is a fourth choice beside light, dark and system (no separate switch); the avatar saves itself as you choose, the last choice winning and a failure rolling back with Retry; the geolocation status is a badge beside its title; LIA's voice, the hands-free panel and the voice-mode description are grouped; avatar style moves to Features โ€บ Identity & Memory beside LIA Style, both redrawn; the connections, the consumption export, the knowledge spaces and the MCP servers are laid out as cards; the routines' week view starts closed; ยซ Rich HTML ยป is ยซ HTML ยป and ยซ HTML Cards ยป ยซ Cards ยป; in French the page is ยซ Rรฉglages ยป and in Spanish ยซ Ajustes ยป, like the navigation. - ๐Ÿท๏ธ **Shorter section names, the old ones still found:** seventeen settings sections take the name their menu shows โ€” ยซ Skill permissions ยป, ยซ My phone ยป, ยซ Data export ยป, ยซ Usage export ยป, ยซ My favorites ยป, ยซ Live voice mode ยปโ€ฆ โ€” in the six languages, the FAQ, the help corpus and the guides; the settings search still finds each one by its former name. - ๐Ÿ“ฑ **On a phone, the companion makes room:** LIA's eyes step away from the search field, buttons and headings, and shrink to a dot when there is no free space โ€” your chosen spot is never overwritten. Opening a settings section moves the focus to it, and ยซ Back ยป returns to the item you came from. - ๐Ÿงญ **Back where you were:** opening a person in Relations keeps the search, the filters and the scroll, accents are ignored and ยซ Clear filters ยป is one tap; the meetings list keeps its page in the address, and ยซ Back ยป from a meeting returns to it. The FAQ opens on its version history. - ๐Ÿ”” **The notifications hub is ยซ Alerts ยป**, like its navigation entry (ยซ Alertes ยป, ยซ Hinweise ยป, ยซ Avisos ยป, ยซ Avvisi ยป). - ๐Ÿ—๏ธ **Build and scan:** the image scan (`task security:scan:docker`) now fails on a HIGH or CRITICAL finding, and the web production image no longer copies the whole package store into its build stage. - ๐Ÿ”’ **Next.js 16.4.1:** the web front moves to the release that closes the advisories published with it โ€” two critical remote code executions and a denial of service through Server Actions, which the settings pages use โ€” and `undici` gets a floor of 7.30.1. The new router's route prediction is switched off (`experimental.optimisticRouting`): the language middleware rewrites every default-language path, and a predicted route made a public page fetch its 1.8 MB layout segment again several times a second; a browser test now names that loop. ### Removed - ๐Ÿงน **The advisory re-planner** ([ADR-346](docs/architecture/ADR-346-Advisory-Replanner-Retired-A-Pipeline-Failure-Is-Said-Never-Replayed.md), superseding ADR-128): the analyzer that followed every failed pipeline plan advised retries and re-plans that nothing ever ran โ€” measured in production, it called ยซ transient ยป each failure of the week, none of which was. It goes with its two metrics and the `ADAPTIVE_REPLANNING_MAX_ATTEMPTS` and `ADAPTIVE_REPLANNING_EMPTY_THRESHOLD` settings (a line left in a `.env` is ignored). A failed step is stated in the answer, a passing outage is retried by the client that met it, a plan the validator rejects is re-planned before it runs, and the ReAct mode remains the one that corrects itself. The FAQ, the How guide, two blog articles and the README no longer describe a recovery that never ran. - ๐Ÿ“ **Two plan step types that never ran** ([ADR-346](docs/architecture/ADR-346-Advisory-Replanner-Retired-A-Pipeline-Failure-Is-Said-Never-Replayed.md), amendment 2026-10-14): `REPLAN`, refused by the validator, and `HUMAN`, accepted then failed at execution. Nothing produced them but a skill template, and no production skill declares one. A test now holds the plan step types equal to what the executor runs. - ๐Ÿ—‘๏ธ **The stale `apps/api/coverage.json`**, a February coverage report at 39 % that nothing read; coverage JSON output is now ignored like the others. - ๐Ÿงน **`BROWSER_MEMORY_LIMIT_MB` and the `browser_memory_bytes` gauge**, which nothing enforced or sampled ([ADR-059](docs/architecture/ADR-059-Browser-Control.md), amendment 2026-10-15); the dashboard shows the API workers' memory instead. - ๐Ÿ—‚๏ธ **The ยซ Why does LIA think this? ยป block under memories, interests and journal entries:** the lists show the entries and their editing actions; the references stay available through the API ([PROVENANCE_AND_CAPABILITIES](docs/technical/PROVENANCE_AND_CAPABILITIES.md)). - โœ‚๏ธ **Screen elements that repeated another one:** the recent-meetings block of the meetings settings and the templates shortcut of the meetings list (both stay reachable from Settings), the alerts hub's ยซ Advanced settings ยป links, the home page's large photo hero. ### Fixed - ๐Ÿณ **The development web container starts after a Next.js upgrade:** its entrypoint now checks that Next.js resolves at the version the manifest names before trusting its install marker, repairs from the frozen lockfile, and stops with the rebuild command when the repair fails โ€” a stale image had served ยซ You are offline ยป on a `MODULE_NOT_FOUND`. - ๐Ÿท๏ธ **The FAQ version history wears its emoji again:** the eleven releases from v2.1.0 to v3.1.0 had lost the emoji that opens every title, in all six languages; a test now holds every title since v1.20.12 to it. - ๐ŸŽš๏ธ **The radio's voices survive a change of model:** they were kept per provider AND model, so every model change of the radio's voice slot handed you other voices โ€” or automatic ones. They are kept per provider now, every model of which offers the same voices, and the choices made on an earlier model are still read. - ๐Ÿ’ก **A light, room or scene that does not exist is no longer ยซ switched ยป:** the Hue commands answered a refused command as done, and LIA said so; they now answer that the target was not found, naming the ones that exist. Every connector tool is held to the same verdict ([ADR-347](docs/architecture/ADR-347-Read-Tool-Data-Reaches-The-Pipeline-Answer-A-Declared-Failure-Is-Never-A-Success.md)): a refusal is never turned into a success on its way to the answer. - โœ… **A task that could not be marked as done is no longer filed as done:** completing a Google task answered in a legacy format no reader of the verdict could read, so a refused completion reached the actions LIA performed, and the tool metrics, as a success. It now reads as the failure it is, and every connector tool answers in the format that carries a verdict. - ๐Ÿ” **A repeated action with one failed item keeps the others:** creating three reminders with one refused lost the confirmations of the two that were created; the answer now confirms them and states the one that failed. - ๐Ÿชž **A person's 360ยฐ overview is read once** in the autonomous mode, where it arrived twice. - โ†ฉ๏ธ **A reply's confirmation shows, and sends to, whom it reaches:** a reply to all no longer loses its other recipients, a reply to your own message no longer goes back to you, and on Outlook and iCloud the card names the recipient. - โœ๏ธ **Asking to ยซ add Paul in copy ยป** while reviewing an e-mail no longer replaces its recipient, and a name after an address in a recipient list is now resolved from your contacts. - ๐Ÿ’ถ **The cost of ยซ Modify ยป on a confirmation** is billed to the turn that asked it. - ๐Ÿ”Ž **An Outlook search keeps what names the mail** ([ADR-287](docs/architecture/ADR-287-Email-Content-First-Detail-Levels-Digests-And-Neutral-Message.md), amendment 2026-10-13): ยซ Marie's unread mails ยป used to list every unread mail, because the sender was dropped whenever a date or the read state came with it (5 searches in 7 days of production), and a person's relationship sheet listed every mail since its date as exchanged with them. The query is now one request Graph accepts; what it cannot carry โ€” dates and read state beside a search, the star โ€” is checked on the page, and a thinner page says how many it set aside. The same holds for the drafts listing, so deleting ยซ my drafts to Marie from last week ยป no longer reaches older ones. - ๐Ÿ“ **An iCloud message is read, trashed, forwarded and opened from its own folder:** its id now carries a digest of the folder, so a message listed in Sent can no longer be confused with the inbox message of the same number, and a forward no longer reads the inbox alone. - ๐Ÿ” **Outlook and iCloud accounts are no longer judged ยซ not connected ยป** in pipeline mode ([ADR-184](docs/architecture/ADR-184-Published-Bounds-And-Non-Prescriptive-Verdicts.md), amendment 2026-10-13): a step's Google scopes are checked only when Google serves it, and a skill keeps the e-mail, calendar and contacts steps another provider serves. - ๐Ÿงฉ **The draft renderers import on their own:** a script or worker importing them first no longer fails on a circular import. - ๐Ÿงญ **A step that ran and failed is no longer reported as ยซ blocked ยป** ([ADR-184](docs/architecture/ADR-184-Published-Bounds-And-Non-Prescriptive-Verdicts.md), amendment 2026-10-14): its failure is told once, by the failures directive, where an authoritative ยซ not connected ยป used to contradict it. ยซ No connector is active for this ยป is now a typed failure that directive explains, in pipeline and ReAct mode alike, so ยซ no mail service is connected ยป stays the answer when it is true. - ๐Ÿ”Œ **A tool of a provider you have not connected is no longer offered:** an Outlook account is no longer proposed Gmail's settings, labels and filters or Google Drive's files, in the chat or on a voice call, so a mail question is served by the mailbox that is connected. - ๐Ÿ“‚ **A search in a folder of your own reads that folder** ([ADR-287](docs/architecture/ADR-287-Email-Content-First-Detail-Levels-Digests-And-Neutral-Message.md), amendment 2026-10-14): Outlook used to read the inbox instead, and iCloud looked for its trash under a name it does not use. A folder is now found by its role or its name whatever its case, and one that does not exist is said with the folders that do. - โž– **ยซ Not from the newsletter ยป is honoured:** negated criteria โ€” a sender, a subject, a date, the read state, the star, and on Outlook an attachment โ€” used to be dropped from Outlook and iCloud searches, which then listed what was excluded. - ๐Ÿ”‘ **A confirmed action that could not run says why** ([ADR-303](docs/architecture/ADR-303-Tool-Failure-Restitution.md), amendment 2026-10-14): its result card used to show an internal code (ยซ EXECUTION_FAILED ยป, ยซ CONFIRMATION_MISSING ยป) or the raw text of an error. It now reads a sentence in your language: a service no longer connected is named with where to reconnect it โ€” Gmail for the vacation responder and filters, Google Drive for sheets and documents, a connector you or an administrator revoked โ€”, a change saved before the failure says so before you retry, and a cancellation that came too late is no longer announced as done. - ๐Ÿ”Š **Remote dictation goes to the engine the administrator configured** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md)): it used to be ElevenLabs whatever the `voice_transcription` slot named, ยซ remote available ยป meant that an ElevenLabs key existed, and the cost was filed under ElevenLabs. The slot's provider now receives the audio, the voice settings name it โ€” so the privacy notice says who receives it โ€” and the cost is filed under it. - ๐Ÿ†“ **A voice that was not served is no longer billed:** a surface whose configured engine could not be served speaks through Edge and costs nothing, where it used to record the configured engine's tariff. - ๐Ÿท๏ธ **A bracketed word in a text read aloud is no longer performed** as a cue by an engine that reads tags, and a `<|speaker:N|>` marker in someone else's words can no longer make another voice speak. - ๐Ÿ“ฆ **`eleven_v4` and `eleven_v4_turbo` reach upgraded instances:** they had joined the seed bundle without a migration. - ๐Ÿ“‰ **A chat answer whose voice ran past its wait is counted** (`voice_fallback_total{reason="timeout"}`): it was voiced again through the direct path while the dashboard showed a clean turn. - ๐Ÿ—ฃ๏ธ **The voice no longer reads LIA's internal tags aloud** ([ADR-253](docs/architecture/ADR-253-Per-Turn-Expressivity-Annotation.md), amendment 2026-10-14): a spoken conversation answer could end on ยซ valence 0.1, arousal 0.1โ€ฆ register warmโ€ฆ ยป โ€” the self-assessment and tone tags the model appends, which the token stream let through attribute by attribute, whatever the speech engine. The stream now removes them across tokens, and the item selection that opens an answer built from your data with them. - ๐Ÿ—ฃ๏ธ **A spoken comment names what the written answer chose** ([ADR-082](docs/architecture/ADR-082-Progressive-Sentence-Streaming.md), amendment 2026-10-14): after a search, the voice could announce a result the answer had left out โ€” on a measured turn, the text proposed four places of twenty-two and the voice named another one, 5 replays in 5 โ€” because the comment was written from every result the tools returned, at times before the answer had even begun. It now starts with the answer and speaks only of the results the answer kept, its lead first, in every domain; when the answer kept none, the voice reads the answer. - ๐Ÿ”’ **A voice provider's refusal no longer carries its words** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md), amendment 2026-10-14): the ElevenLabs and OpenAI transcription clients kept up to 512 characters of the vendor's answer in their errors, ElevenLabs speech and its voice listing 200 in their messages โ€” and a validation refusal echoes the field it refused, the sentence being voiced included. A refusal now travels by its status and the vendor's code, and is logged by those facts; the build fails on any new excerpt of a response body in a client. - ๐Ÿ—„๏ธ **The administration's voice pickers no longer hold a database connection while a vendor lists its voices** ([ADR-304](docs/architecture/ADR-304-No-Transaction-Across-A-Network-Call.md)): each request authenticates on a session of its own, closed before the vendor is asked. - ๐Ÿ”‘ **A refused ElevenLabs key is named in dictation too:** the live dictation reported an unidentified HTTP error where the meeting transcription already said the key was refused; both now read the vendor's code. - ๐Ÿ”Š **An OpenAI voice failure is read from its type:** a refusal whose message held ยซ generate ยป was treated as a rate limit, a timeout as an HTTP error and a refused key as a missing one, and a request the vendor refused for good was tried again; it no longer is. - ๐Ÿ“Š **The ยซ Voice Comment Tokens ยป panel shows the comment's tokens** (dashboard 11): it charted a metric only an uncalled function wrote; it now reads the tokens every spoken comment's model call records. - ๐Ÿ”ข **The getting-started and observability guides quote the real metric count:** they said 606 and 419. Both figures are now held to the source by the release check, and the observability guide points at the dashboard catalogue instead of stale dashboard and runbook counts. - ๐Ÿงช **The browser flatteners' linearity test no longer fails under a loaded suite:** it read one tick of the Windows thread clock (15.6 ms) as an infinite growth; it now reads CPU over batches of calls, alternating the two sizes, and decides on the median. - ๐Ÿงช **The API's timed tests no longer fail on a loaded host:** two asynchronous tests ordered their steps with sleeps, which a starved event loop wakes in one iteration, and now wait on the events themselves; the machine-tag filter's linearity guard read the wall clock, which counts the wait for a processor as work (a linear filter read ร—8.6 and ร—10.2 with every core busy), and now reads the thread's CPU like the flatteners' guard, through a clock precise on Windows too (`tests/support/thread_clock.py`); a cold-import check's 30 s budget became the hang guard it was meant to be. - ๐Ÿงช **The browser's source guards no longer fail on a loaded suite:** eleven guards read the whole `src/` tree inside a test, whose 15 s budget vitest checks only after a synchronous body returns, so it measured the host โ€” four turned red on a clean tree, one file taking 49.6 s under coverage. They now read it once, at collection, through one scanner (`src/__tests__/source-scan.ts`) that refuses to run inside a test. - ๐Ÿงช **The stored-file tests no longer pass a changed file off as intact on Windows:** nine cases rewrote a file with the same size right after observing it, and a stat identity cannot see a same-size write inside one tick of the filesystem's clock โ€” the deletion cleanup's case failed 133 times in 500, the move staging's 232. They now write a LATER change, new bytes stamped past any tick (`tests/support/file_clock.py`): 0 failures in 500 each. - ๐Ÿ” **A ยซ for each ยป over names or places sends each one to its step:** a bare `$item` whose item was a string reached the step's parameters with its own quotes inside theirs, the parameters no longer parsed, and the step ran with the literal `$item` โ€” found by a live proof on Docker dev, where three walking routes went to Google with destination `$item` and answered ยซ no route ยป. The substitution now works on the parameters themselves: an object or a list arrives whole, a value inside a text reads as text, nothing is re-parsed. - ๐Ÿงช **The integration suite is green again in CI:** the voice readout test merges real audio through ffmpeg, which the integration job now installs (the API images already ship it), and the Fish Audio key fence expects a person's voices under the provider, where they have been kept since the radio voices fix. - ๐Ÿ“ป **The radio says the name you gave your station** ([ADR-324](docs/architecture/ADR-324-A-Personal-Radio-A-Grid-Decides-Models-Only-Write.md), amendment 2026-10-14): the host used to welcome you to ยซ LIA ยป whatever the station was called โ€” measured on dev, nine openings in ten โ€” because the writer was given the name only once, beside LIA's. It is now told the name wherever a programme names the station, and LIA as the assistant who runs it: ten openings in ten said the station's name. - ๐ŸŽจ **The stylesheet is built from the application's sources alone:** Tailwind also read the 1 064 test files (2 504 files in all, past the guard's bound); it now reads the 1 440 sources, which drops 22 rules no production file used. The guard's witnesses can no longer be produced by its own text. - ๐Ÿ”ข **A ยซ for each ยป step whose items failed no longer counts one failure too many** ([ADR-346](docs/architecture/ADR-346-Advisory-Replanner-Retired-A-Pipeline-Failure-Is-Said-Never-Replayed.md)): the loop's summary inherited its items' failure and was counted beside them, so one failed item was announced as two, two as three. - ๐Ÿงฉ **The skill guide and the skill generator name the one step type a plan template runs, `TOOL`** ([ADR-346](docs/architecture/ADR-346-Advisory-Replanner-Retired-A-Pipeline-Failure-Is-Said-Never-Replayed.md), amendment 2026-10-14): the guide offered `REPLAN` and `HUMAN` in six languages and the generator `PARALLEL` and `RESPONSE`, none of which ran. Any other type now refuses the template before execution, and the request goes to the regular planner. - ๐ŸŽญ **Personalities have their character back** ([ADR-068](docs/architecture/ADR-068-Psyche-Engine.md), amendment 2026-10-16): the reference seed re-created the 14 stock personalities without their Big Five and mood profile, so on every instance seeded after the traits arrived, all of them reacted like ยซ Normal ยป. Migration `b62a8d193f04` restores the profiles where no administrator set a value and aligns a psyche still at the neutral profile โ€” mood, emotions and relationship untouched โ€”, the seed check now refuses a profile without traits, and an account that never chose a personality follows the default one. - ๐Ÿ”ฌ **A delegated expert that runs out of steps still delivers** ([ADR-083](docs/architecture/ADR-083-Sub-Agent-Delegation-React.md), amendment 2026-10-13 b): its last call writes the analysis from what it found, where it used to end on LangGraph's ยซ Sorry, need more steps to process this request ยป, reported as a success. Browser and MCP tasks say how far they got when they fail, an MCP task keeps the widgets it created, and a skill that produced no answer says why (`subagent_outcomes_total{agent_name,outcome}`, dashboard 19). - ๐Ÿ“ **Both modes tell an expert's reach the same way** ([ADR-083](docs/architecture/ADR-083-Sub-Agent-Delegation-React.md), amendment 2026-10-13): the autonomous mode no longer delegates ยซ analyse my e-mails ยป to an expert that cannot read them, and the instruction's size cap is enforced by the tool in both modes, before any model runs. - ๐Ÿšฆ **Web searches wait out a provider's rate limit instead of failing** ([ADR-108](docs/architecture/ADR-108-BaseAPIKeyClient-Adoption.md), amendment 2026-10-13): a 429 on one person's Brave or Perplexity key opened a breaker every account shares and refused 13 searches of 15 in one run, read as ยซ service unavailable ยป. It is now retried with jitter; when it persists it reads ยซ rate limit ยป โ€” the briefing's weather card included โ€” and Perplexity failures are no longer counted as successes. - โฑ๏ธ **A tool LIA's own limiter refuses is a refusal** ([ADR-303](docs/architecture/ADR-303-Tool-Failure-Restitution.md), amendment 2026-10-13): it was recorded as a consulted source, a successful call and a productive iteration; it now states the limit, whose it is and when it lifts. - ๐Ÿ” **A routine never asks a question nobody can see** ([ADR-263](docs/architecture/ADR-263-Execution-Authority-Chain-And-Effect-Register.md), [ADR-276](docs/architecture/ADR-276-Workboard.md), [ADR-298](docs/architecture/ADR-298-Sandbox-Egress-Toolbox.md), amendments 2026-10-13): thirteen routine runs had stopped on a confirmation or a sandbox-network question that took your next message as its answer and held back later routines. A routine now refuses and says where to allow it; a ticket still asks. - ๐Ÿ›‘ **A routine or a ticket retried after a timeout never repeats what it did** ([ADR-276](docs/architecture/ADR-276-Workboard.md), amendment 2026-10-13 b, [ADR-265](docs/architecture/ADR-265-Routine-Week-Timeline-And-Run-History.md)): a retry replayed the whole turn, browser tasks included; it is refused once the register shows an action. A routine's reservation is held by its token, so the recovery never hands a live run to a second tick and a late settle never overwrites another tick's routine. - ๐Ÿ’ฌ **ยซ LIA is already working on this conversation ยป** ([ADR-117](docs/architecture/ADR-117-Background-Chat-Runs.md), amendment 2026-10-13): while a ticket or a voice relay runs on your conversation, the chat says LIA is busy; it no longer attaches to a stream nobody writes or claims a Stop worked, and a message sent meanwhile says it was not sent. - ๐Ÿ“ก **Live streams through a compressing proxy** ([ADR-117](docs/architecture/ADR-117-Background-Chat-Runs.md), amendment 2026-10-15): event streams carry `Cache-Control: no-transform`, so a gzip proxy no longer holds the notifications and the chat until they end. - ๐Ÿ”• **Signing a device out also stops its notifications** ([ADR-144](docs/architecture/ADR-144-Device-Sessions.md), amendment 2026-10-13): the notification stream kept flowing to a revoked tab; it now closes with `session_revoked` and the page returns to the sign-in instead of reconnecting into refusals. - ๐Ÿ—“๏ธ **One scheduler, even after a lost lease** ([ADR-046](docs/architecture/ADR-046-Background-Job-Scheduling.md), [ADR-123](docs/architecture/ADR-123-Lifespan-Startup-Decomposition.md), amendments 2026-10-13): a worker that lost its lease kept running every job beside the new leader; it now pauses until it is re-elected, and a shutdown starts no job and stops the scheduler before what its jobs need. - ๐ŸŒ **Web pages load on hosts without IPv6** ([ADR-326](docs/architecture/ADR-326-Linear-Flatteners-And-Pinned-Fetches.md), amendment 2026-10-13): the validated address was picked in hash order and could be an unreachable IPv6 one; the resolver's order is kept, and a refused connection moves to the next validated address. - โœ‰๏ธ **An e-mail is sent once:** sends, replies and forwards on Gmail, Outlook and iCloud are no longer retried after a lost acknowledgement, which could deliver them twice; a send some recipients refused says how many received it. - ๐Ÿ“Ž **A forward never drops a file silently, and a reply honours Reply-To** ([ADR-344](docs/architecture/ADR-344-Mailbox-Drafts-Kept-Freely-Sent-After-One-Confirmation.md)): a file that cannot be downloaded refuses the forward before anything is written. - ๐Ÿ—‘๏ธ **iCloud moves mail to its real trash:** found by its role, never a folder named ยซ Trash ยป, and without expunging what other mail apps had marked deleted; a ยซ not found ยป answers at once instead of after seconds of retries. - ๐Ÿ **The iCloud connection test checks every service you selected** โ€” mail, calendars, contacts โ€” and says in your language whether the password, the certificate or the connection failed. - ๐Ÿ”’ **A connector cannot be activated past a revocation** ([ADR-302](docs/architecture/ADR-302-OAuth-Grant-Par-Compte-Et-Consentement-Groupe.md), amendment 2026-10-15): an activation re-reads your account and the administrator's switch under locks once the provider has answered, and a provider key is written in one atomic step ([ADR-215](docs/architecture/ADR-215-Self-Host-Installer.md), amendment 2026-10-15). - ๐Ÿ“จ **ยซ Send me this by e-mail ยป no longer asks for a recipient**, and ยซ prepare a draft ยป no longer asks for content LIA writes itself: the missing-content check matched tool names by fragment. - ๐Ÿ“ญ **A mailbox that could not be read is not ยซ empty ยป:** when every message read fails, LIA says so instead of answering that you have no mail. - ๐Ÿ“ฒ **Long Telegram messages keep their formatting:** a long HTML message is split between tags, each part closing what it opened; parts used to be refused and resent as raw text with the tags visible. - ๐Ÿ›ก๏ธ **The third-party content envelope holds in every spelling** ([ADR-167](docs/architecture/ADR-167-Content-Trust-Registry.md), amendment 2026-10-13): a closing tag written in another case, full-width or with invisible characters can no longer break out of it, and the injection scan reads the text as a model does. - ๐Ÿ”‘ **Secrets stay out of logs and answers** ([ADR-317](docs/architecture/ADR-317-A-Log-Line-Carries-Facts-Never-The-Words.md), amendments 2026-10-13 and 2026-10-15): provider keys, a quoted `Bearer` or `api_key` and card numbers are masked; connector, Places, Routes, geocoding, Microsoft Graph and telephony refusals carry their status and code, never the provider's text; a sandbox run or a network skill command removes a key the remote service echoed ([ADR-298](docs/architecture/ADR-298-Sandbox-Egress-Toolbox.md), amendment 2026-10-13 b); the web app no longer logs push tokens. - ๐Ÿ–ฑ๏ธ **Browser refusals are typed** ([ADR-303](docs/architecture/ADR-303-Tool-Failure-Restitution.md), amendment 2026-10-14): a page that could not be read is no longer ยซ empty ยป, and the browser agent's prompt names the click and fill argument as the tools do. - ๐Ÿ“‰ **Compaction's token counts are recorded:** `compaction_cost_tokens_total` read 0 on every real call. - ๐Ÿ”‡ **The chat keeps speaking when its voice engine cannot be served:** Edge stood in with the configured engine's voice ids, which mean nothing to it, so the answer was silent; it now speaks with Edge's own voices. - ๐Ÿ“ป **The briefing's ยซ Read aloud ยป reads the whole text** on an engine that returns raw audio: each sentence came back as its own file and the joined file played only the first; the sentences are now encoded as one MP3. - ๐Ÿ›‚ **A voice slot names a model its provider serves:** saving Fish Audio with an ElevenLabs model, a transcription model on a speech slot or a model priced in a unit the recorder cannot read is refused; such a slot used to be served as the vendor's default model while LIA priced it at another tariff. - ๐Ÿ” **A voice-library act stops when its author loses the right to it** ([ADR-345](docs/architecture/ADR-345-Fish-Audio-Served-Whole-One-Door-One-Allowance-Cues-Each-Engine-Reads.md), amendments 2026-10-15): clone, design, save, rename, delete, pin and unpin re-read the administrator's role when they act, a designed voice is saved once, and a preview never goes to another vendor account than the one that generated it. Deleting a voice gives everyone who had chosen it the instance's voice back. - ๐ŸŽ™๏ธ **A meeting on a transcription account without credit fails at once** instead of retrying until its attempts run out. - ๐Ÿ”„ **Briefing cards retry where they failed:** on a network or rate-limit error, ยซ Retry ยป refreshes the card, where the agenda, mail and weather cards sent you to the connectors settings. - ๐Ÿงพ **An error is never an empty list:** meetings that could not load no longer read ยซ No meeting yet ยป, calls ยซ hidden ยป, plugins ยซ No plugin installed ยป or the alerts counts ยซ โ€” ยป; each says it could not load, offers Retry and keeps the rows already shown. The scheduled section of the alerts shows different rows on each page. - ๐ŸŽง **A second press cancels a briefing that is still loading its voice**, which could otherwise start playing late. - ๐Ÿ‘€ **The Smiley companion keeps its 3D context** when the page re-mounts it, and a preferred spot just outside the margin no longer sends the companion to the opposite edge. - ๐ŸŒ **Language and time zone follow the server's confirmation:** a refused change no longer stays displayed, and changing the language keeps the open settings section. - ๐Ÿงฉ **A plugin manifest with an explicit `null` in an optional field is refused**, like a wrong type. ## [3.0.1] - 2026-10-13 **A portrait that reads everything LIA keeps about you, and lighter ReAct turns.** The compiled portrait becomes an analysis of the person again, fed by nine sources read whole, with a brief written as a summary of its own; a journal change no longer erases it. ReAct binds fewer tools per turn, stops recovering from pages it was never meant to finish, and hands the graph only what a turn changed. API workers keep their vectors compact and freeze their startup heap. Twenty-three dependency advisories are fixed or accepted with a written reason, and the landing's use-case times are readable in the light theme. ### Added - ๐Ÿชž **The portrait reads nine sources, whole** ([ADR-343](docs/architecture/ADR-343-Portrait-Reads-The-Whole-Material-And-Its-Brief-Is-A-Synthesis.md)): memories, interests, learned habits and relationship debriefs are joined by open loops, Workboard tickets, routines, reminders and kept answers, each offered through the shared seam with its own gates and an exact total. Five caps โ€” three per source, a per-item clamp and a global character cap โ€” give way to ONE bound, a share of the consolidation slot's context window (`JOURNAL_CONSOLIDATION_SOURCES_WINDOW_FRACTION`), and a cut is stated in the provenance and on the settings card. - ๐Ÿง  **An analytical portrait with a real brief:** the consolidation reads the person across the sources on seven facets (posture, focus, context, rhythm, tension, interaction, uncertainty), names a pattern instead of listing its items, and writes the brief as its own two or three claims rather than a prefix of the full text. Every admitted reading is published; stored portraits are recompiled once under the new policy. - ๐Ÿงช **Measurement tooling:** `scripts/journals/measure_portrait.py` measures the portrait on a seeded, inert persona with oracles shared with admission; `scripts/react/selection_corpus.json` replays tool selection over 45 questions; `scripts/ops/worker_census.py` counts what a live worker holds by types and sizes only. ### Changed - ๐Ÿ›ก๏ธ **No model reviews the portrait's readings:** the second, semantic review call is removed (measured rejecting grounded readings even after two recalibrations of its criterion). What refuses invention is structural: a reading cites items of the current snapshot, a paragraph restating one item, a name the cited items carry or a figure, address or date in the prose is dropped. One model call per consolidation again. - ๐Ÿ•ฐ๏ธ **A journal change marks the portrait stale, never empty:** the settings card says a recompilation is pending, the ambient block always carries its compilation date, and deleting entries withdraws only the readings they supported. - ๐Ÿ”ง **Repaired before refused:** a claim or a maintenance action the snapshot cannot carry is repaired (a facet, an abstraction level) or dropped alone and counted; a single faulty item no longer voids a paid consolidation. - ๐ŸŽฏ **ReAct binds a catalogue through its domain** ([ADR-293](docs/architecture/ADR-293-React-Tools-Bound-By-Relevance.md) amendment): a binding unit never rides the relevance tail, and a family of many units โ€” the settings catalogue โ€” is reached through its routed domain. Measured on real rankings: an agenda turn binds 67 tools instead of 140, a settings turn 103 instead of 243. The application-settings prompt block is rendered only when a settings tool is bound; the tool cap's bound rises to 500. - โšก **The graph input is the turn's diff** ([ADR-022](docs/architecture/ADR-022-LangGraph-State-Checkpointing.md) amendment): the restored state is no longer replayed whole into the graph, so unchanged channels take no new checkpoint version on every turn. What the model reads is untouched. - ๐Ÿ” **A page cut at a tool's cap is not a gap** ([ADR-336](docs/architecture/ADR-336-Requested-Outcomes-Checked-Against-Canonical-Observations.md) amendment): only a failed read reaches the bounded recovery pass; requested outcomes and gaps the model declares keep their behaviour. - ๐Ÿงฎ **Compact worker memory** ([ADR-283](docs/architecture/ADR-283-Worker-Memory-Anatomy.md) amendment): tool-selection vectors are `float32` arrays (about eight times smaller than Python float lists), a user's MCP vectors are parsed once per catalogue and worker (`MCP_SERVER_VECTOR_CACHE_MAX`), an MCP argument model is built once per schema (`MCP_ARGS_SCHEMA_CACHE_MAX`), the startup heap is frozen last in the lifespan, and a BM25 index is replaced when its corpus changes. - ๐Ÿ“‰ **Leaner observability:** cAdvisor and postgres-exporter are scraped on keep-lists with lighter cAdvisor housekeeping ([ADR-333](docs/architecture/ADR-333-Linked-Signals-And-A-Pipeline-That-Watches-Itself.md) amendment); the public demonstrator runs two API workers. ### Fixed - ๐Ÿ”’ **Dependency advisories:** aiohttp 3.14.4, dnspython 2.9.0, LangGraph 1.2.14 with its SDK 0.4.6, OpenTelemetry 1.45.1, DOMPurify 3.4.17, i18next 26.4.4 and Vite 8.3.4, each fix held by a floor in its manifest (ADR-331); the APScheduler advisory, unpatched upstream, is accepted with its reason โ€” LIA uses the in-memory job store only. truststore 0.10.5 closes two TLS verification advisories published on release day. - ๐ŸŽฌ **Landing films kept across deliveries:** the historical public films stay in the playlist after a new render, their bytes checked by fingerprint. - ๐ŸŽจ **Readable use-case times in the light theme:** the step times of the landing's use cases were bright cyan on light glass (1.7:1, found by axe on Firefox); a text cut of the accent cyan (`--cosmos-cyan-ink`) holds AA on every light ground, kept by the cosmos contrast guard. - ๐Ÿงญ **Weekly browser matrix green again:** the Firefox and WebKit run read Playwright's blind spots as product failures. A check an engine cannot expose (WebKit's intercepted cookies and multipart content, a redirect fulfilment, a subframe download outside Chromium) is asserted where it is observable and named elsewhere as an `engine-limit` annotation; headless Firefox gets a virtual display for WebGL, the companion sphere is measured at the page's own density, and a touch tap waits for the page to come to rest. - ๐Ÿณ **API image:** runtime manual pages needed by package alternatives are retained, package installs are declared non-interactive, and CI image builds export to the cache only. - ๐Ÿ—„๏ธ **Schema comments** of the portrait columns describe what they hold since ADR-343 (migration `0ff858a07321`); a timing-sensitive unit test of the source worker renewals waits on its events instead of a fixed delay. ### Documentation and installation - ADR-343 added; ADR-022, ADR-079, ADR-283, ADR-293, ADR-308, ADR-333 and ADR-336 amended; journals, ReAct execution, Grafana dashboards and the worker memory runbook updated; FAQ, guides, knowledge base and living maps follow. - New settings are optional with defaults (`JOURNAL_CONSOLIDATION_SOURCES_WINDOW_FRACTION`, `MCP_SERVER_VECTOR_CACHE_MAX`, `MCP_ARGS_SCHEMA_CACHE_MAX`); five portrait source caps are removed. A fresh self-hosted install needs no new answer. ## [3.0.0] - 2026-10-12 **Requests connected to their context, with results you can inspect.** This release brings supported application management into conversation, strengthens structured outcome verification and publishes an editable product presentation. Native companions, public explanations and operating documentation evolve together. Experimental options retain their stated qualification limits. ### Added - **Application management through conversation:** account-scoped tools inspect and change supported preferences and objects. Minor reversible settings use their declared policy; creations, deletion and sensitive operations request confirmation. Encrypted expiring commands retain actor, origin, operation digest, phase and current authority. Browser-native file, private-input and connector authorization continuations keep their existing controls (ADR-339). - **Requested-outcome verification:** explicit obligations are checked against canonical structured observations, including values, operation, account and completeness. Drafts, opaque results and delegation announcements cannot prove execution. Compact verdicts survive checkpoints and reach bounded recovery and final synthesis (ADR-335, ADR-336). - **Checkpointed ReAct reads:** eligible independent read segments run with bounded concurrency and publish results before later interruption. Exact, fresh, complete results can be reused within the same turn and authority context; mutations invalidate reuse. Unknown, interruptible, delegated and mutating calls keep sequential execution (ADR-337). - **Live MCP contracts:** current input/output schemas, structured output, schema age and hashes travel with the callable contract. Administrative and user-owned targets preserve exact identity independently of public aliases; delegation is bound before policy, approval and invocation (ADR-338). - **Native body volume:** reviewed original avatar artwork supplies bounded anatomical relief, alpha coverage, normals and facial projection under the existing rig. Graphics lifecycle and unavailable-resource fallbacks are explicit; full physical anatomy and arbitrary facial occlusion remain approximations (ADR-340). - **Product film and complementary focuses:** editable HTML/CSS/Remotion construction, original electro-funk soundtrack provenance, complete native avatar catalogue, contextual male Lumo, display modes, reminders, Relations, populated planning, action register, administrative views and dedicated PWA sequence. Complete native screens remain stationary outside declared element focuses; crops preserve the original rows and geometry (ADR-341). - **Exclusive Presentation player:** blue CTA before the guided demo, explicit full-film manifest descriptor, lazy fullscreen dialog, native controls, localized loading/error/retry states and background playback suspension. The neighboring registration CTA is removed. The film and checked editable construction are linked from README and release assets. - **Optional one-time BIP campaign:** a deployment-scoped runtime identifier applies the companion style on the next authenticated browser visit, with persisted completion, later manual choices preserved, multitab coordination where available and storage-failure rollback. Empty remains the installation default; this is not a database avatar preference (ADR-342). ### Changed - **Semantic context:** resolved references keep their value, kind and source through query intelligence and the shared Pipeline/ReAct argument guard. Dates and places cannot be silently treated as contacts. Tool dependencies require constructible canonical evidence rather than phantom producers. - **JEV decisions:** native Choice/Noul criteria and bounded parameter-kind observations retain debug evidence and attribution. Deterministic compatibility, authorization and HITL stay in code. Parameter-kind assistance is opt-in and disabled by default; uncertain outcomes do not remove existing guards. Offline qualification findings are documented without inferring production gains (ADR-325 amendments). - **Public content:** FAQ and end-user/admin release notes, relevant blog material, six-language durable presentations, knowledge exports and functional/technical/decision maps reflect the delivered features. Public explanations distinguish implemented safeguards and supported standards from certification claims. - **Landing on phones:** spacing and separators clarify the assistant promise, journey benefits and three individually centered trust statements. Application screenshots share the Grafana carousel's presentation frame. - **Model catalogue:** the repository's reviewed model/pricing seeds include the added Anthropic model records; configured instance slots remain the runtime authority rather than following a forced global retarget. ### Fixed - The Presentation retry explicitly refreshes unavailable or outdated metadata, bypassing browser caches while coalescing and throttling origin requests. - Memory extraction records a consent-sensitive revision and refuses stale writes after a concurrent revision or deletion. Routine generation uses a reservation that settles the current generation without racing another tick. - Scheduled sandbox egress approvals retain their action buttons and pending state when messages synchronize after the scheduled run. - Tool-result cards restore their terminal disclosure behavior; conversation history search and light-theme chip icon contrast retain readable native UI. - Radio respects the first requested programme's priority. Existing commercial and editorial source controls remain in place. - Voice sentence cleanup retains linear processing and removes native provider tags without reordering rendered audio. - Its growth regression test measures current-thread CPU time to exclude descheduling under load, while preserving the wall-time ceiling, growth thresholds and a deliberately quadratic negative witness. - Weather input distinguishes explicit from omitted dates, validates supported units and states accepted dates instead of silently replacing unreadable ones. - Semantic taxonomy, enum examples and producer ownership are aligned with the actual executable registry rather than unavailable declarations. - Deployment preserves SOPS UTF-8 text on Windows and regenerates the Docker group identity needed by the existing isolated skill runner. Sandbox Docker denial has an explicit availability outcome instead of a successful claim. - Beat-map selection preserves bounded timing and an explicit analysis version; exported music and source provenance stay attached to their actual edit. ### Documentation and installation - Added ADR-339 through ADR-342 and guides for application commands, native avatar volume, motion production and JEV semantic qualification. Updated affected implementation references and architecture maps. - Version surfaces, changelog references and derived public counts use the repository's release tooling. Public test/source figures are fresh measurements, not projected counts. - Installer and backend configuration contracts cover the delivered migrations, startup wiring and optional runtime UI setting. Clean-host candidate qualification and release promotion remain bound to exact image digests. ## [2.6.1] - 2026-10-06 **Une voix continue, un avatar maรฎtrisรฉ et une interface ร  portรฉe de main.** Cette version fiabilise la restitution existante, le contrรดle de la session Simli et le placement des fenรชtres sur mobile. Lโ€™avatar demeure expรฉrimental : les essais fournisseur et physiques Android/iOS restent ร  qualifier. ### Changed - **Contrรดle de la session avatar** : lโ€™API possรจde le WebSocket fournisseur ; un ticket ร  usage unique remplace le jeton fournisseur dans le navigateur. Le jeton et la clรฉ de fermeture restent chiffrรฉs cรดtรฉ serveur. Signalisation et PCM traversent le relais ; le mรฉdia WebRTC retournรฉ reste fournisseurโ€“navigateur. Prรฉsence validรฉe, rรฉvocation du ticket et fermeture de la gรฉnรฉration exacte permettent de rรฉconcilier une session aprรจs rechargement sans prendre celle dโ€™un autre onglet. Un arrรชt brutal du serveur reste bornรฉ par le plafond fournisseur. - **Prรฉsentation publique** : captures renouvelรฉes avec donnรฉes fictives, manifeste de rรฉvision et workflow de capture reproductible ; galerie, README, documentation, FAQ, prรฉsentations et cartes vivantes actualisรฉs dans six langues. ### Fixed - **Radio** : amorรงage silencieux stรฉrรฉo alignรฉ sur les morceaux de la station, pour fiabiliser le dรฉmarrage natif sous WebKit. Le geste de lecture, les deux pistes et la protection contre une pause tardive sont conservรฉs. - **Couverture CI** : rapports backend XML et frontend JSON archivรฉs dans GitHub Actions pendant sept jours, avec erreur explicite si le rapport manque. Les seuils restent imposรฉs par les mรชmes tรขches locales et CI. Le lancement manuel de la mรชme CI permet de qualifier le commit exact dโ€™une branche de release lorsque `main` avance en parallรจle. - **Scan de secrets** : faux positifs historiques examinรฉs individuellement et enregistrรฉs par empreinte exacte de commit, fichier, rรจgle et ligne ; scan complet conservรฉ et dรฉtection dโ€™une nouvelle valeur synthรฉtique vรฉrifiรฉe. - **Dรฉpendances CSS** : correctifs de dรฉni de service pour `source-map-js` ([GHSA-68fv-2mgg-jv7q](https://github.com/advisories/GHSA-68fv-2mgg-jv7q)) et le parseur de sรฉlecteurs utilisรฉ par Typography ([GHSA-rj75-hqrm-r3gf](https://github.com/advisories/GHSA-rj75-hqrm-r3gf)). Rรฉsolution figรฉe, compatibilitรฉ de gรฉnรฉration CSS vรฉrifiรฉe et audits rejouรฉs. - **Avatar** : bouton dโ€™arrรชt conservรฉ hors de la frontiรจre dโ€™erreur du chat, avec rรฉsultat confirmรฉ ou en attente ; erreurs sรปres, contrรดle de prรฉsence et fermeture vรฉrifiรฉe avant libรฉration du bail. Les traces de signalisation masquent le ticket de connexion. - **Live et restitution** : file PCM bornรฉe et cadencรฉe par la lecture rรฉelle pour les longues rรฉponses ; ordre conservรฉ, fin et annulation nettoyรฉes, absence de reprise locale dโ€™un prรฉfixe potentiellement dรฉjร  audible. - **Mobile et PWA** : placement de lโ€™avatar, du compagnon et des raccourcis bornรฉ au viewport visuel, y compris clavier, rotation, zoom et panoramique. Les ajustements temporaires ne rรฉรฉcrivent pas la prรฉfรฉrence ; instantanรฉs gรฉomรฉtriques stables et coordonnรฉes finies รฉvitent les boucles de rendu. - **Galerie** : URLs de captures rรฉvisรฉes et autorisation locale ciblรฉe dans lโ€™optimiseur dโ€™images pour servir les images actualisรฉes. Le lecteur agrandi est montรฉ hors des sections animรฉes pour couvrir tout le viewport. - **Structure HTML** : badges en ligne, description composรฉe des espaces RAG, commande dโ€™activation des personnalitรฉs et attribut boolรฉen des iframes respectent la sรฉmantique HTML et รฉvitent les avertissements de rendu React. Les descriptions des sources Radio sรฉparent explicitement les mots annoncรฉs. ### Tests - **Radio** : format WAV, silence, durรฉe, correspondance des canaux avec les morceaux livrรฉs et rรฉsolution tardive de la lecture contrรดlรฉs ; parcours natifs avec lecture, redimensionnement et arrรชt conservรฉs. - **Garde de croissance linรฉaire** : temps CPU du thread mesurรฉ sur plusieurs appels et tailles alternรฉes, avec mรฉdiane des ratios, pour distinguer le travail du code des variations de charge sous xdist ; plafond de durรฉe rรฉelle, tรฉmoins et seuils conservรฉs. Le motif quadratique historique reste explicitement refusรฉ. - Contrats avatar PostgreSQL, Redis et WebSocket, arrรชt et restitution, longues rรฉponses Live, stabilitรฉ de disposition et prรฉfรฉrences flottantes. - Parcours navigateur hermรฉtiques : clavier/PWA et avatar sur mรฉdia simulรฉ. Ils ne certifient ni mouvement des lรจvres fournisseur ni compatibilitรฉ matรฉrielle. - Matrice Firefox/WebKit : sortie audio native virtuelle, STUN local et silence du pair synthรฉtique ; thรจme chargรฉ dรจs lโ€™amorรงage et assertions de phase compatibles avec lโ€™horloge mise en pause, sans retirer les rรจgles dโ€™accessibilitรฉ. Horloges suspendues avant navigation, geste de lecture aprรจs montage de lโ€™historique et alignement mesurรฉ aprรจs les deux peintures diffรฉrรฉes. Captures de cartes dimensionnรฉes ร  leur contenu aprรจs les contrรดles axe, puis retour au viewport auditรฉ ; seuils, dรฉlais et rรจgles conservรฉs. Le compagnon conserve chaque frame active ; les pรฉriodes de repos sont avancรฉes sous la limite du rig, avec la mรชme durรฉe virtuelle totale. La composition attend la rรฉponse et la rรฉouverture effective du formulaire avant de sรฉlectionner une seconde carte archivรฉe. Chromium utilise le navigateur complet รฉpinglรฉ en mode headless documentรฉ, avec lโ€™ensemble des rรจgles axe, scรฉnarios mรฉdia et assertions gรฉomรฉtriques. - Isolation API conservรฉe pendant la fermeture des navigateurs : requรชtes en attente annulรฉes, notifications de sortie bloquรฉes et preuve par serveur local sur les trois moteurs. Les appels inattendus conservent leur erreur explicite. Une garde de transport par contexte couvre les envois keepalive dรฉtachรฉs de Chromium et refuse les tunnels opaques sans remplacer le document d'รฉchec. La vraie police d'icรดnes est รฉpinglรฉe et servie localement pendant les scans, avec provenance et licence, pour mesurer les glyphes sans dรฉpendance au CDN. Les rรฉsultats axe complets traversent des blocs bornรฉs avec contrรดle de longueur et dโ€™empreinte avant assemblage ; toute altรฉration รฉchoue explicitement. Les callbacks diffรฉrรฉs finissent dans leur test ; les attentes externes sont annulables. Les parcours de recherche chargent le thรจme du compte avant navigation ; le dรฉfilement vรฉrifie sรฉparรฉment lโ€™envoi et la fin des rรฉponses immรฉdiates ou diffรฉrรฉes. - Opรฉrations asynchrones des tests React attendues jusquโ€™ร  leur rรฉsultat ; interactions et changements de stores regroupรฉs avec les mises ร  jour React. - Installateur : prรฉsence avatar รฉmise et alignรฉe avec les Settings ; aucun nouveau service Compose, seed, rรฉglage obligatoire ou parcours de boot. Le contexte de build web exclut les artefacts temporaires de validation et de capture ; un build de production sans cache conserve lโ€™installation figรฉe. ## [2.6.0] - 2026-10-05 **Un visage pour la voix, des sources plus lisibles et des coรปts traรงables.** L'avatar parlant personnel Simli accompagne les commentaires vocaux et les conversations Live, sur activation explicite et avec une seule restitution audible. Cette intรฉgration reste expรฉrimentale : les essais physiques et la qualification de la restitution rรฉelle sont encore attendus. Les cartes identifient mieux leurs sources, les nouvelles consignes permanentes sont รฉpinglรฉes et Radio distingue l'information utile des sollicitations commerciales. La consommation conserve le prix de chaque tentative rapportรฉe par le fournisseur, y compris en cas d'รฉchec. ### Added - **Avatar parlant personnel Simli, expรฉrimental** : connecteur ร  clรฉ personnelle chiffrรฉe, permission du compte dรฉsactivรฉe par dรฉfaut, catalogue de visages et fenรชtre flottante ร  trois tailles, dรฉplaรงable au clavier, au toucher et ร  la souris. Un port commun de restitution accompagne les commentaires et le Live direct ou dรฉlรฉguรฉ sans nouveau modรจle ni synthรจse. Le mode actif conserve la connexion ; la veille Live la ferme et le rรฉveil en demande une nouvelle. Une session ouverte peut consommer des crรฉdits personnels pendant le silence. Admission Redis partagรฉe par clรฉ, crรฉation sans reprise implicite, issue inconnue mise en quarantaine et renouvellement aprรจs fermeture vรฉrifiรฉe. Radio reste hors pรฉrimรจtre. [Conception proposรฉe](docs/architecture/ADR-334-Personal-Speaking-Avatar-And-One-Audible-Output.md) et [qualification](docs/technical/SPEAKING_AVATAR.md). - **Supprimer depuis une carte e-mail** : la composition prรฉpare la confirmation existante avant mise ร  la corbeille. Le compte source est recontrรดlรฉ ร  la prรฉparation, ร  la reprise et aux opรฉrations fournisseur ; une ancienne carte n'obtient pas une permission de suppression nouvelle. - **Deux usages JEV indรฉpendants et dรฉsactivรฉs par dรฉfaut** : prรฉsence de rรฉfรฉrences personnelles avant rรฉsolution mรฉmoire et refus complet d'une confirmation. Une dรฉcision incertaine conserve le parcours gรฉnรฉratif et ne vaut jamais autorisation d'exรฉcution. ### Changed - **Consommation par tentative** : modรจle, instant de dรฉbut, tarifs et conversion USD/EUR sont retenus ensemble avant l'appel. Les tokens de cache, รฉchecs payรฉs, reprises et annulations sont comptabilisรฉs sans repricer ni doubler une tentative. Les tรขches hors conversation, les synthรจses et les coรปts d'instance suivent le mรชme contrat ; une lecture manquante n'invente pas une consommation. - **Qualifications JEV** : une opรฉration conserve son instantanรฉ de routage et de prix sur tous ses lots. Le diagnostic distingue candidats, รฉvaluรฉs, inconnus et omis, ainsi que la sรฉlection native et son rรฉsultat applicatif. Les comparaisons de date et fuseau restent calculรฉes dans le code ; les aperรงus conservent les donnรฉes canoniques et ne deviennent pas des actions. - **Mรฉmoire** : les nouvelles consignes permanentes sont รฉpinglรฉes dรจs leur crรฉation. La personne peut les corriger, les dรฉsรฉpingler ou les supprimer ; les automatismes respectent l'รฉpinglage et la protection de catรฉgorie. - **Prรฉsentation publique** : le catalogue fonctionnel est conservรฉ sans la section redondante de cas d'usage. Prรฉsentations, FAQ, recherche des rรฉglages, connaissances et cartes vivantes sont actualisรฉes dans les six langues. ### Fixed - **Radio** : filtrage des publicitรฉs, partenariats, promotions et invitations ร  acheter, sans supprimer factures, rรฉservations, rendez-vous et vรฉritables publications รฉditoriales. Caches รฉditoriaux sรฉparรฉs et lecture ciblรฉe des sections nรฉcessaires. Le PCM/ยต-law TTS porte sa frรฉquence et son encodage avant FFmpeg ; l'annulation ne supprime pas un fichier final prรฉexistant. Le bandeau ne dessine plus de bord noir autour du contenu. - **Cartes MCP** : origine publique du serveur et mรฉthode restent visibles, rรฉponse sous un dรฉtail accessible, sans publier chemin, query ou identifiants de l'URL de connexion. Les rรฉponses objet, tableau et scalaire restent consultables. Un cooldown partagรฉ et bornรฉ absorbe les refus de dรฉbit sans transformer un rafraรฎchissement en rafale d'appels. - **Mรฉtรฉo** : codes du fournisseur et observation jour/nuit conduisent les pictogrammes, avec brouillard, vent et orage distincts, dans les observations, prรฉvisions quotidiennes et horaires ; la traduction du texte ne choisit plus le symbole. - **Voix et Live** : fin de production, silence, interruption, veille et reprise traversent la mรชme frontiรจre de sortie. Les files audio conservent l'ordre et nettoient leur propre mรฉdia sans arrรชter les pistes empruntรฉes au fournisseur. - **Confidentialitรฉ des diagnostics** : les messages internes et รฉvรฉnements fournisseur passent par la rรฉdaction des champs de contenu ; les traces de l'avatar ne conservent ni voix, transcription, clรฉ ni URL signรฉe. - **Journal et facturation** : une consolidation conserve sa trace d'รฉchec lorsque le modรจle a rรฉpondu mais que l'enregistrement de facturation รฉchoue ; elle ne crรฉe pas d'acte pour un modรจle qui n'a jamais rรฉpondu. - **Installateur** : le parcours propose l'avatar comme intรฉgration optionnelle, รฉmet ses bornes cohรฉrentes et conserve tous les choix aprรจs une reprise, y compris le diagnostic autonome qui revenait ร  sa valeur par dรฉfaut. - **Dรฉmonstrateur** : sa construction et son exรฉcution API utilisent la version et le commit du bundle dรฉployรฉ ; le pilote de production refuse une provenance absente au lieu de dรฉmarrer avec une identitรฉ de dรฉveloppement. - **Dรฉpendances** : plancher `asyncssh` relevรฉ au correctif 2.24.1 de la traversรฉe de chemins SFTP (GHSA-q8m6-9rfx-39rf) ; Starlette utilise l'import actuel de `BlockingPortal`, sans masquer l'avertissement AnyIO. - **Veille des dรฉpendances** : les dรฉpรดts dรฉplacรฉs conservent leur lecture authentifiรฉe sur la mรชme origine ; une redirection vers un autre hรดte, port ou protocole ne reรงoit jamais le credential. Les requรชtes GitHub sont espacรฉes entre workers, une coupure rรฉseau bรฉnรฉficie d'une seule reprise et toute source non lue reste un รฉchec explicite du contrรดle. ### Tests - Rรฉgressions comportementales des cartes et de leur compte source, mรฉtรฉo, cooldown MCP, mรฉmoire รฉpinglรฉe, JEV par lots et facturation des appels payรฉs interrompus ; mixage Radio sur vrais fichiers audio et transitions persistรฉes. Le corpus navigateur conserve une horloge de rรฉfรฉrence fixe pour ses dates relatives ; la provenance dรฉmo est vรฉrifiรฉe par le shell et Compose rรฉels. - Avatar : admission et rรฉvocation, baux partagรฉs, annulation, conversion PCM, interruption, renouvellement, une seule sortie audible et parcours navigateur avec un pair WebRTC local. Ces simulations ne prouvent pas le mouvement labial Simli ni la compatibilitรฉ physique Android/iOS, rรฉservรฉe aux essais du propriรฉtaire. ## [2.5.0] - 2026-10-04 **Des cartes qui montrent tout ce qui a รฉtรฉ reรงu et des actions qui appartiennent ร  leur message, une application aux couleurs du cosmos, des signaux d'observabilitรฉ qui se rรฉpondent.** Les rรฉponses porteuses de donnรฉes deviennent des cartes dรฉterministes qui affichent tout ce que la source a fourni sans rien inventer, gardent le dรฉtail complet derriรจre des dรฉpliants accessibles, s'enrichissent de galeries, de comparaisons mรฉtรฉo, d'aperรงus de documents et d'itinรฉraires interactifs comptรฉs, et permettent de rรฉpondre, transfรฉrer ou ajuster un rappel depuis la carte ([ADR-332](docs/architecture/ADR-332-Deterministic-Cards-Received-Facts-And-Message-Owned-Actions.md)) ; le modรจle ne relit qu'une vue sรฉmantique, jamais le HTML. Le fond animรฉ de la page d'accueil s'รฉtend ร  l'application, les surcouches adoptent un verre dรฉpoli, le tableau de bord gagne une carte Workboard et les rรฉglages se rรฉorganisent ; une rรฉponse gardรฉe dit ses deux coรปts. Dans Grafana, journaux, traces et mรฉtriques s'ouvrent les uns les autres et la chaรฎne d'observation se surveille elle-mรชme ([ADR-333](docs/architecture/ADR-333-Linked-Signals-And-A-Pipeline-That-Watches-Itself.md)). La page d'accueil enchaรฎne deux vidรฉos, avec un bouton pour passer ร  la suivante. ### Added - **Cartes dรฉterministes des rรฉponses** (ADR-332) : rendu serveur unique, adaptateurs typรฉs par famille et primitives partagรฉes (titre, texte complet, faits, dรฉpliants natifs) ; un fait reรงu est montrรฉ en entier et jamais inventรฉ โ€” absent, zรฉro et faux sont trois รฉtats, l'horloge source passe par un seul analyseur (`core/time_parsing.py`), la rรฉcurrence native de Microsoft reste native. E-mails (corps complet, piรจces jointes, parties), contacts (toutes les organisations et leurs dates, tรฉlรฉphones, adresses, anniversaires, notes), agendas (alias visible, accรจs, rappels, tous les points de connexion d'une visioconfรฉrence, rรฉcurrence), tรขches (notes, sous-tรขches), fichiers (propriรฉtaires, droits, vignettes fournies), lieux (photos attribuรฉes en galerie plein รฉcran, avis complets, horaires par pรฉriode), trajets (รฉtapes, transports, alternatives fournies, pรฉages), mรฉtรฉo (crรฉneaux comparables), recherches (extraits complets, citations liรฉes ร  leur source), Hue, tickets et rรฉsultats MCP (instantanรฉs bornรฉs, champs d'identifiants masquรฉs). Ouvrir un dรฉtail n'appelle ni fournisseur, ni modรจle, ni outil. - **Aperรงus de documents gรฉnรฉrรฉs** : premiรจre page d'un PDF (agrandissable), extrait d'un CSV ou d'un classeur, premiers paragraphes d'un Word, couverture d'une prรฉsentation โ€” lus sous les contrรดles de propriรฉtaire, de statut et d'expiration du fichier, dans un processus isolรฉ et bornรฉ pour MuPDF, jamais mis en cache ni envoyรฉs au modรจle. - **Itinรฉraires interactifs** : une carte de trajet s'ouvre en carte Google (SDK Maps JavaScript) sur la gรฉomรฉtrie exacte du fournisseur, toutes les alternatives tracรฉes, sรฉlection mise en avant, fonds plan/satellite/hybride/relief ; activation explicite avec coรปt estimรฉ, clรฉ libรฉrรฉe seulement aprรจs admission authentifiรฉe sous les plafonds du compte et de l'instance et une autorisation signรฉe de courte durรฉe, chaque construction enregistrรฉe sous une exรฉcution durable (aucun schรฉma ajoutรฉ). `GOOGLE_MAPS_BROWSER_API_KEY` (facultative, sinon `GOOGLE_API_KEY`) et le tarif `maps_javascript` du seed Google ; sans eux, aucune activation n'est offerte. - **Rรฉpondre depuis une carte** : rรฉpondre, transfรฉrer un e-mail ou ajuster un rappel prรฉpare la demande dans la zone de saisie avec une pastille de contexte ; le serveur relit la rรฉponse d'origine, la source et le droit du compte au clic, et HITL, modification, reprise et nouvel essai revรฉrifient la mรชme liaison. Aucune action pour une source sans liaison structurelle de compte (Apple Mail). - **Carte Workboard du tableau de bord** : comptes exacts (ce qui t'attend, ce que tient LIA, en retard, ouverts), chacun menant au tableau filtrรฉ, puis les premiers tickets qui t'attendent ; configurable comme les autres cartes, masquรฉe quand l'instance รฉteint le Workboard (`BRIEFING_MAX_WORKBOARD_ITEMS`). - **Les deux coรปts d'une rรฉponse gardรฉe** (amendement ADR-282) : ce qu'elle a coรปtรฉ ร  produire (la ligne de synthรจse de son tour, retrouvรฉe par le `run_id` copiรฉ au clic โ€” colonne `message_bookmarks.run_id`, migration `b6e2d8f4a1c7`) et ce qu'a coรปtรฉ son indexation, chacun nommรฉ ; jamais un zรฉro que personne n'a mesurรฉ. - **Un bouton ยซ Lire la vidรฉo suivante ยป** dans le cadre et le lecteur ancrรฉ de la page d'accueil, qui enchaรฎne dรฉsormais deux vidรฉos en boucle, chacune avec son crรฉdit et sa carte des temps (amendement ADR-330). - **La chaรฎne d'observation se surveille elle-mรชme** (ADR-333) : Loki, Alloy, Tempo et Grafana scrutรฉs sur une liste `keep` chacun (une vingtaine de sรฉries), alerte `LogsNotDelivered` (recette, requรชte de catalogue, runbook, tests promtool), ligne ยซ Observability pipeline ยป du tableau 16, garde `test_pipeline_keep_lists_guard`. ### Changed - **Le fond animรฉ de la page d'accueil derriรจre l'application** : le shell connectรฉ et les pages de connexion portent `AppCosmos` ; l'en-tรชte et les panneaux restent pleins, le fil du chat est un verre lรฉger entre ses bulles. Une seule matiรจre de tuile (`DashboardTile`) pour les cartes du tableau de bord, et le code couleur des domaines (`lib/domain-tone`) colore aussi les puces du centre de notifications. - **Un verre dรฉpoli pour toutes les surcouches** (`lia-overlays.css`) : fenรชtres, menus, listes, info-bulles, visionneuses et notifications (Sonner en mode `unstyled`), opaques sous transparence rรฉduite ou couleurs forcรฉes, focus rendu ร  l'รฉlรฉment d'origine. - **Rรฉglages rรฉorganisรฉs** : icรดnes des connecteurs et des domaines, santรฉ (statistiques puis graphiques), rรฉseau du bac ร  sable, serveurs MCP en deux colonnes avec leur description, appels rรฉcents repliรฉs, compรฉtences, espaces de connaissances gรฉrรฉs directement, habitudes et ยซ Rรฉunions ยป en sections repliables. - **Le modรจle lit une vue sรฉmantique versionnรฉe de chaque rรฉponse** (`display/model_history.py`, `infrastructure/llm/message_view.py`), jamais le HTML des cartes : un corps d'e-mail retenu par le mode ยซ mรฉtadonnรฉes ยป ne revient plus au tour suivant par la carte. - **Grafana : les signaux s'ouvrent les uns les autres** (ADR-333) โ€” journal โ†’ trace (champ dรฉrivรฉ sur le `trace_id` JSON), trace โ†’ journaux et mรฉtriques (`$__tags` rรฉtabli), latence โ†’ trace (stockage des exemplars sous `traceID`) ; `job` nomme le service compose ; chaque tableau s'ouvre sur 7 jours (journaux et traces sur 4 h) avec un menu ยซ LIA dashboards ยป commun, tenu par `test_grafana_dashboard_conventions_guard` ; mรฉmoire de production Prometheus 768 Mo, Loki 384 Mo avec cache de rรฉsultats. - **Le scan de secrets suit tous les parents entrants** : les commits d'une branche fusionnรฉe et le contenu d'une rรฉsolution de conflit sont scannรฉs (`--diff-merges=first-parent`, `test_secret_scan_merge_lineage.py`). - **La configuration Vitest est un module ESM natif** (`vitest.config.mts`). ### Fixed - **Le coรปt d'indexation des documents des espaces de connaissances** est celui que l'embedder a facturรฉ (`billed_embedding_usage`) : le tokenizer et la table de prix OpenAI de l'ingestion le sous-estimaient d'environ 7ร— pour chaque document indexรฉ par Gemini. - **La photo du compte Google** revient dans l'avatar du chat : une URL conservรฉe pouvait servir la silhouette `default-user`, et Google signe une nouvelle URL ร  chaque connexion โ€” elle est rafraรฎchie ร  chaque connexion Google ; une image potentiellement Google passe par le proxy (un avatar relatif rรฉpondait 500 sur dev). - **Une phrase sans rien ร  prononcer** n'est plus envoyรฉe au moteur TTS (facturรฉe puis refusรฉe) ; un รฉchec TTS est journalisรฉ par son code. - **Tempo** : overrides au format scopรฉ, adresse du worker, tolรฉrance ร  la course rรฉtention/poller (30 รฉchecs par jour) ; **Grafana** : provisioning `plugins/` et `alerting/` valides, plus d'auto-traรงage (59 % des spans) ; **l'API** : un span par requรชte et non par message ASGI (88 %) ; **Alertmanager** n'affiche plus d'adresse ; marqueur d'arrรชt de Loki dรฉfini. - **`PushWakeSweepStalled`** passait en attente avec 18 rรฉveils servis sur 18 : chaque sรฉrie fournisseur ร— issue est exportรฉe ร  zรฉro dรจs l'import. - **Un SKU Google tarifรฉ ร  zรฉro est gratuit**, pas manquant ; les requรชtes Gemini dรฉsactivent l'appel de fonctions automatique de google-genai (`ChatGeminiNoAfc`). - **Les migrations** configurent la journalisation avant d'importer les modรจles et n'appellent plus `fileConfig` ; un `ToolMessage` orphelin est journalisรฉ en DEBUG. - **La carte interactive atteint une instance mise ร  jour** : le tarif `maps_javascript` n'รฉtait que dans le seed, qu'une instance existante ne rejoue jamais โ€” la carte y restait dรฉsactivรฉe (mesurรฉ sur la production) ; la migration `ef46f93d7745` l'ajoute lร  oรน aucun prix actif n'existe, sans toucher un prix saisi par un administrateur, et une garde exige qu'un tarif Google datรฉ aprรจs l'audit du 23 septembre voyage par une migration. - **`task test:e2e` tourne sur un poste Windows** : le `NODE_ENV=development` du `.env` chargรฉ par le Taskfile faisait mourir le build gรฉrรฉ au prรฉrendu, le prรฉfixe `PORT=` du serveur รฉtait un nom de programme pour `cmd.exe`, et le parcours du verre lisait la prรฉfรฉrence de transparence du systรจme hรดte ; `lia-overlays.css` n'est plus importรฉ deux fois. ### Tests - Corpus de rรฉfรฉrence des cartes gรฉnรฉrรฉ depuis les vrais producteurs (`tests/helpers/card_reference_cases.py`), refusant toute dรฉrive entre le backend et le corpus que lisent le frontend et les parcours navigateur ; fidรฉlitรฉ par domaine avec zรฉro, faux, absences, valeurs non finies et entrรฉes hostiles ; 45 parcours hermรฉtiques Chromium/Firefox/WebKit dont les dรฉtails natifs, la galerie, les itinรฉraires et la composition ; test de concurrence sur PostgreSQL jetable pour l'admission des cartes. - Les parcours navigateur du tableau de bord et des rรฉglages suivent la carte Workboard et les sections repliรฉes ; deux suites d'intรฉgration RAG fournissent `model_name` au calcul des coรปts. - Conventions des tableaux Grafana, listes `keep` de la chaรฎne d'observation, matrice des destinataires Alertmanager et redaction des requรชtes Alloy gardรฉes par des tests. ## [2.4.0] - 2026-10-03 **Des dรฉpendances qui mรปrissent avant d'entrer et ne reculent jamais, une tรฉlรฉmรฉtrie qui ne nomme personne, une page d'accueil qui respire.** Un programme complet de cycle de vie des dรฉpendances ([ADR-331](docs/architecture/ADR-331-Dependency-Watch-And-A-Refresh-That-Never-Goes-Back.md)) : une veille hebdomadaire lit ce qu'aucune porte ne voyait (avis publiรฉs par chaque projet, fins de vie, registres, moteur du navigateur), un rafraรฎchissement attend un dรฉlai de prudence et ne recule jamais, chaque entrรฉe du build de production est รฉpinglรฉe par empreinte, et un scan de secrets prรฉcรจde chaque push. La pile d'observabilitรฉ passe sur des versions maintenues, Alloy remplace Promtail, et les mรฉtriques comme les traces nomment la route empruntรฉe โ€” jamais un nom ni une recherche. FastAPI 0.141, OpenTelemetry 1.44, webauthn 3, SQLAlchemy 2.0.54, React 19.3 et Playwright 1.63 entrent avec la preuve de ce qu'ils changent ; la matrice navigateurs (Chromium, Firefox, WebKit), rouge depuis onze semaines, repasse au vert et a trouvรฉ deux vrais dรฉfauts d'interface. La page d'accueil gagne un fond animรฉ ยซ attention ยป, un pied de page en verre dรฉpoli posรฉ sur la planรจte et une vidรฉo fondue dans la page, et chaque page publique peut mettre ses animations en pause ; ยซ Dis LIA ยป est rรฉentraรฎnรฉ et ยซ LIA, stop ยป coupe dรฉsormais la voix de LIA. ### Added - **Veille des dรฉpendances** (ADR-331) : `task deps:watch` lit ce qu'aucune porte ne voit โ€” les avis de sรฉcuritรฉ que chaque dรฉpendance publie dans son propre dรฉpรดt (la revue en a trouvรฉ vingt absents de la base GitHub), les fins de vie, les faits des registres et le moteur du navigateur โ€” contre des acceptations datรฉes et motivรฉes (`scripts/audit/dependency_watch_accepted.json`) ; le workflow hebdomadaire `dependency-watch.yml` ouvre ou met ร  jour UNE issue, et la veille est une รฉtape de chaque release, jamais une porte de pull request. Un constat se corrige ou s'accepte avec une raison et une date de revue, jamais en silence. - **Un rafraรฎchissement qui attend et ne recule jamais** (ADR-331) : `task deps:refresh` (remplace `deps:upgrade:all`) dรฉplace le verrou Python sous un dรฉlai de prudence comptรฉ depuis la version EN PLACE โ€” 5 jours pour un correctif, 14 pour une mineure, 60 pour une majeure, une mineure sous 1.0 comptant comme une majeure โ€” et refuse tout recul de version, qu'un dรฉlai global d'uv aurait provoquรฉ. Un correctif de sรฉcuritรฉ transitif devient un plancher de manifeste (dix planchers posรฉs). Dependabot suit la mรชme doctrine : dรฉlais de prudence partout, alertes seules pour pip, regroupement docker-compose, suite e2e couverte. - **Des gardes qui n'ont pas besoin du rรฉseau** : chaque import dรฉclarรฉ dans un manifeste, chaque entrรฉe de build รฉpinglรฉe, une image = une rรฉfรฉrence dans tous les fichiers compose et tous les workflows, un seul propriรฉtaire par version (pnpm, promtool, uv, Node, l'image Playwright de la CI tenue รฉgale au paquet e2e), et les รฉtiquettes des images d'observabilitรฉ citรฉes par la documentation tenues ร  leur source. - **Scan de secrets avant chaque push** : `task security:secrets` exรฉcute le gitleaks de la CI (mรชme version, mรชme configuration) sur ce que le push envoie, depuis le hook `pre-push` โ€” un secret parti sur le dรฉpรดt distant ne se reprend pas. - **Fond animรฉ ยซ attention + espace latent ยป de la page d'accueil** : un canevas posรฉ derriรจre la page (`AttentionBackdrop`, `lib/landing/attention-background.ts`) dessine un nuage d'embeddings qui se regroupe au fil du dรฉfilement โ€” un point de requรชte y allume ses plus proches voisins โ€” et, ร  droite, une colonne de jetons oรน chaque section devient un repรจre ; son intensitรฉ suit le temps de la musique de la vidรฉo. Il monte quand le navigateur est au repos, perd sa colonne sous 768 px, se fige si ses images dรฉpassent un budget de 5 ms et ne laisse rien au dรฉmontage. Les lignes du titre d'accueil battent chacune leur tour, le pied de page devient un bandeau de verre dรฉpoli posรฉ sur la planรจte de la derniรจre section, et la vidรฉo se fond dans la page par une fine bande et un halo rythmรฉ, que la scรจne du lecteur (`.landing-video-stage`) rogne aux bords de la page (posรฉ en coordonnรฉes document, il รฉlargissait le document de 14 % de la largeur du cadre). - **Le CLI DevOps nomme son modรจle et son effort** : `DEVOPS_CLAUDE_MODEL` et `DEVOPS_CLAUDE_EFFORT` sont transmis ร  chaque exรฉcution (`--model`, `--effort`), en local comme en SSH, par une seule construction des arguments ; le CLI s'authentifie avec son PROPRE jeton longue durรฉe (`CLAUDE_CODE_OAUTH_TOKEN`, crรฉรฉ par `claude setup-token`). - **Mettre les animations en pause (WCAG 2.2.2)** : la nรฉbuleuse, les nuages de la planรจte et le fond animรฉ dรฉmarrent seuls et durent plus de cinq secondes ; chaque page publique porte dรฉsormais un bouton de pause (`MotionToggle`, `aria-pressed`, nom stable) โ€” dans l'en-tรชte ร  partir de 1280 px (en dessous, la rangรฉe de liens n'a pas la place : mesurรฉ, il la faisait dรฉborder de 33 ร  49 px en franรงais), dans le menu mobile et dans chaque pied de page. L'รฉtat tient en un attribut `data-motion="paused"` sur `` (`lib/landing/motion-pause.ts`) : la feuille de style met en pause les animations de la portรฉe cosmos, le canvas le lit ร  chaque image, les scรจnes de `/more` le partagent ; le choix est retenu pour le visiteur. - **La matrice navigateurs exรฉcute la suite** : `task test:e2e:browsers` lance les mรชmes parcours sur Chromium, Firefox et WebKit, et le workflow hebdomadaire l'appelle au lieu de dรฉfinir sa propre commande (la garde de paritรฉ CI le lit dรฉsormais). ### Changed - **Kit MCP 2.2** : un serveur ajoutรฉ par une personne ne choisit plus ce que l'API va chercher โ€” une rรฉfรฉrence `$ref` distante dans le schรฉma de rรฉsultat d'un outil n'est plus tรฉlรฉchargรฉe (GHSA-rwrf-2pqf-9j8j) et une redirection vers une autre origine n'est plus suivie ; une rรฉfรฉrence interne au schรฉma et une redirection de barre oblique sur la mรชme origine continuent de fonctionner, prouvรฉes contre de vrais serveurs locaux. - **Le navigateur de l'outil de navigation est le Chromium de Debian**, mis ร  jour avec la distribution (amendement [ADR-059](docs/architecture/ADR-059-Browser-Control.md)) ; un lancement ratรฉ est comptรฉ et le moteur journalisรฉ au dรฉmarrage. **Une seule version de KaTeX** sert l'affichage des formules. - **FastAPI 0.141.1 et OpenTelemetry 1.44** : depuis la 0.137, un routeur inclus est un nล“ud de l'arbre des routes ; trente modules de tests lisent les routes servies par un seul parcours (`tests/_routes.served_routes`), tenu par une garde AST. - **webauthn 3.0.0, cbor2 6.1.4, SQLAlchemy 2.0.54** : les passkeys proposent Ed25519 en premier ; SQLAlchemy corrige un `UPDATE โ€ฆ RETURNING` dรฉsalignรฉ sous concurrence et une connexion asyncio laissรฉe ouverte aprรจs un รฉchec d'initialisation. - **Tous les jetons JWT passent par PyJWT** : un jeton d'identitรฉ sans destinataire est refusรฉ, `at_hash` reste vรฉrifiรฉ par LIA, et un lien de rรฉinitialisation รฉmis avant le dรฉploiement s'ouvre aprรจs. - **Observabilitรฉ sur des versions maintenues, รฉpinglรฉes par empreinte et rรฉpรฉtรฉes sur dev** : Prometheus 3.13.3, Alertmanager 0.34.1, Grafana 12.4.11, Loki 3.7.8, Tempo 2.10.8, exporteurs, cAdvisor et Portainer ร  jour. **Grafana Alloy remplace Promtail** (le service garde son nom `promtail` et la mรชme configuration de masquage) : sans les positions hรฉritรฉes que Promtail rรฉรฉcrivait ร  chaque sauvegarde, sa mรฉmoire passe de 255 Mio (la limite de production) ร  110 Mio, et aucune statistique d'usage ne part chez l'รฉditeur. - **Chaque entrรฉe du build de production est รฉpinglรฉe** : PostgreSQL 16.15 avec pgvector 0.8.6, Redis 7.4.11, Python 3.14.7 (mรชme empreinte que le bac ร  sable), Node 24.21.0 avec ses sommes de contrรดle, rรฉvision et empreinte du modรจle Whisper, CLI Claude Code 2.1.287 โ€” jamais une version antรฉrieure ร  celle que la production exรฉcute. Le dรฉmonstrateur suit (Caddy 2.11.4, cloudflared 2026.9.3, Squid 6.14, Postfix 5.1.0, collecteur OpenTelemetry 0.161). - **Versions rafraรฎchies sous dรฉlai** : 75 mouvements Python (PyMuPDF s'importe dรฉsormais sous son nom `pymupdf`, msgpack โ‰ฅ 1.2.3) et 34 dรฉpendances npm directes, dont React 19.3.0 et eslint-config-next 16.3.5. - **Les notes vocales Telegram sont dรฉcodรฉes par ffmpeg**, sous-processus bornรฉ comme tous les autres chemins audio : la conversion des รฉchantillons passe de 712 ms ร  33 ms et ne bloque plus le serveur (amendement [ADR-241](docs/architecture/ADR-241-Python-3.14-Trixie-Migration.md)). - **Playwright 1.63 et l'image `noble`** pour toute la suite e2e ; **zod** est configurรฉ sans compilation ร  la volรฉe (`@/lib/zod`, imposรฉ par ESLint) : sa sonde `Function("")`, refusรฉe par la CSP, รฉtait signalรฉe comme une erreur JavaScript sous Firefox. - **Boรฎte ร  outils du mot d'activation** : la commande d'arrรชt s'entraรฎne dรฉsormais sous la forme ยซ LIA, stop ยป ; les nรฉgatifs Multilingual LibriSpeech sont tirรฉs locuteur par locuteur (quinze heures au plus chacun), la validation franรงaise compte 74 heures avec de la musique et de l'anglais jamais entendus ร  l'entraรฎnement, un point de contrรดle est notรฉ aussi sur sa forme รฉcrite la plus faible, et chaque banque et chaque cache enregistrent la recette ou les empreintes dont ils viennent, pour ne reconstruire que ce qui a changรฉ. - **ยซ Dis LIA ยป rรฉentraรฎnรฉ, ยซ LIA, stop ยป pour couper la voix** (amendement [ADR-329](docs/architecture/ADR-329-Live-Standby-And-Multilingual-Wake-Word.md)) : dรฉcision du propriรฉtaire, le rappel d'abord โ€” manquer un vrai ยซ Dis LIA ยป est pire qu'un rare dรฉclenchement sur une phrase voisine. Le modรจle franรงais est rรฉentraรฎnรฉ (voix naturelles rรฉgรฉnรฉrรฉes depuis les seuls locuteurs d'entraรฎnement, cible de fausses alarmes du dev publiรฉe) et livrรฉ ร  un point de fonctionnement plus sensible ; la commande d'arrรชt devient ยซ LIA, stop ยป (`phrases.ts`, manifeste, empreintes de rรฉfรฉrence, textes publics ร—6). Les deux modรจles restent `no-go` au banc, donc en bรชta, et le manifeste garde leurs mesures. - **Le dรฉploiement ne copie plus la session Claude du poste** sur le serveur (une session OAuth sur deux machines meurt au premier rafraรฎchissement) et avertit quand DevOps est actif sans jeton dรฉdiรฉ. ### Removed - `python-jose`, `ecdsa`, `rsa` et leurs stubs, avec la derniรจre exception tolรฉrรฉe par `pip-audit` (CVE-2024-23342) ; `pydub` et `audioop-lts` ; cinq dรฉpendances npm jamais importรฉes (devtools, headlessui, react-hook-form, autoprefixer, @hey-api/openapi-ts) ; l'image Promtail ; la tolรฉrance d'avertissement `Connection._cancel` d'asyncpg et sa garde (F028), devenues inutiles avec SQLAlchemy 2.0.54 ; la tรขche `deps:upgrade:all`. ### Security - **Dรฉcompression bornรฉe** : un corps de rรฉponse compressรฉ est lu sous un plafond ; un codage non demandรฉ (brotli) est refusรฉ avant tout dรฉcodage, comme une panne de transport que chaque appelant sait dรฉjร  traiter. - **Aucun nom dans les mรฉtriques ni dans les traces** (prolonge [ADR-317](docs/architecture/ADR-317-A-Log-Line-Carries-Facts-Never-The-Words.md)) : la jauge des requรชtes en cours, รฉtiquetรฉe avant le routage, gardait le chemin brut โ€” un nom sous `/relations/{name}` restait une sรฉrie Prometheus pour toute la vie du processus, et chaque scan en ouvrait une ; elle prend le gabarit que le routage choisira, lu sur les expressions du routeur. Les traces exportรฉes ร  Tempo portaient la cible concrรจte (`http.target`, `http.url` avec sa chaรฎne de requรชte) : un crochet de l'instrumentation la rรฉรฉcrit au gabarit. - **Un scan de secrets avant chaque push** (voir Added) et la correction de six constats gitleaks des lots (une fixture, un exemple, deux noms de sommes de contrรดle). - **`braces` (GHSA-vfj7-8cjw-p6xm, รฉlevรฉ, aucun correctif publiรฉ)** : atteint uniquement par le greffon Next.js d'ESLint (`fast-glob` โ†’ `micromatch`), en dรฉveloppement, sur des motifs que le dรฉpรดt รฉcrit ; acceptรฉ par son identifiant dans `pnpm.auditConfig.ignoreGhsas` โ€” jamais par un niveau d'audit abaissรฉ โ€” et inscrit avec sa raison et sa date de revue dans `docs/technical/CI_CD.md`. ### Fixed - **L'exercice de restauration des sauvegardes รฉchouait depuis le 29 juillet** (un rรดle manquant) : il recrรฉe les rรดles source sans mot de passe et passe de nouveau. - **Le Prometheus du dรฉmonstrateur interrogeait une cible inexistante** depuis la v1.29.0. - **Les mรฉtriques HTTP perdaient le prรฉfixe des routes** depuis FastAPI 0.137 (`/rag-spaces/{space_id}/documents` au lieu de `/api/v1/rag-spaces/{space_id}/documents`) : le libellรฉ est le gabarit SERVI. Une mauvaise mรฉthode rรฉpondait 500 au lieu de 405 et une trace รฉtait nommรฉe d'aprรจs le chemin concret. - **Une note vocale Telegram avait deux plafonds** : 120 secondes ร  l'entrรฉe, puis celui de la transcription (60 secondes par dรฉfaut) โ€” une note de 90 secondes recevait ยซ je n'ai pas compris ยป. Un seul plafond dรฉsormais, le plus petit des deux, pour le refus (annoncรฉ en secondes), et pour le dรฉcodage, qui s'arrรชte juste aprรจs lui quelle que soit la durรฉe dรฉclarรฉe par l'expรฉditeur. Un ffmpeg absent ou qui dรฉpasse son dรฉlai est une erreur de l'instance, plus ยซ le fichier de l'expรฉditeur ยป. - **Le bouton ยซ Revenir en bas ยป du chat** restait collรฉ ร  la fin de la conversation, hors de l'รฉcran, puis sous la zone de saisie : il est dessinรฉ au-dessus de la zone de saisie. - **Le sรฉlecteur de personnalitรฉ** mesurait 43,97 px de large sous WebKit pour une cible tactile de 44 px. - **Le fond des pages cosmos** masquait la nรฉbuleuse, les รฉtoiles et le grain depuis leur crรฉation ; l'anneau de la vidรฉo ne s'รฉtait jamais dessinรฉ ; la lueur du titre des cartes รฉtait rognรฉe. - **Contraste du thรจme clair** (relecture ร  froid du fond animรฉ) : avec le ciel plus soutenu et la nรฉbuleuse visible, l'encre attรฉnuรฉe tombait ร  4,4:1 sur le verre du pied de page et 3,5:1 sous un trait du canvas, le badge ยซ BETA ยป ร  4,18:1 ; `--cosmos-mut` est rรฉaccordรฉ dans les deux thรจmes et le badge passe au rouge 800 โ€” mesurรฉ au pixel aprรจs correction : liens du pied de page โ‰ฅ 5,9:1, badge 5,6:1. Une garde compose dรฉsormais le sol, le ciel, la lueur, le verre et le trait du canvas (`cosmos-contrast.guard.test.ts`). - **Le fond animรฉ ne bouge plus quand il doit รชtre immobile** : sous mouvement rรฉduit, en pause ou sur un appareil trop lent, il dessine une image fixe, redessinรฉe seulement au changement de thรจme ou de mise en page โ€” il suivait encore le dรฉfilement et le pointeur, et recalculait son graphe de voisins ร  30 images/s, plus cher figรฉ qu'animรฉ. Sans `requestIdleCallback` (WebKit), il attend l'รฉvรฉnement `load` au lieu de monter pendant l'hydratation ; aucune langue n'est plus รฉcrite en dur dans le module. - **Le rail des chapitres s'efface quand le pied de page arrive** : passรฉ sous le verre, ses liens n'รฉtaient plus cliquables (4 ร  7 sur 7 selon la hauteur d'รฉcran). La planรจte prolongรฉe est rognรฉe par une classe et non plus par `:has()`, absent de certains moteurs. - **Une identitรฉ git de test** fuyait dans la configuration du dรฉpรดt de l'appelant. ### Tests - Matrice navigateurs mesurรฉe dans l'image de la CI : 1 089 parcours passรฉs, 18 รฉcartรฉs nommรฉment, aucun รฉchec โ€” causes รฉtablies avant correction (service worker hors des simulations rรฉseau, sonde de zod refusรฉe par la CSP, flux de notifications simulรฉ en รฉchec, media queries rรฉรฉvaluรฉes aprรจs deux images, saisie effacรฉe par l'hydratation, vidรฉo en boucle impossible sous le WebKit de Playwright). - Cรฉrรฉmonie passkey de bout en bout sur les vraies bibliothรจques (EdDSA, ES256, clone, origine รฉtrangรจre, format non textuel, passkey synchronisรฉe 0 โ†’ 0) ; contrat d'instrumentation OpenTelemetry sur une application imbriquรฉe rรฉelle ; libellรฉ avant routage รฉgal au routage de FastAPI sur 2 947 requรชtes ; notes vocales Telegram (plafond, dรฉcodage bornรฉ, nature de la panne) ; fond animรฉ et battement du titre ; script de dรฉploiement (Pester). Une garde refuse un `filterwarnings` qui ignore sans nommer de message. Les tests du lecteur vidรฉo dรฉmontent avant de restaurer leurs simulations mรฉdia : le ยซ Not implemented: HTMLMediaElement.pause() ยป de jsdom ne sort plus ร  chaque passage. - Le parcours e2e local redevient hermรฉtique pour la vidรฉo de la page d'accueil : `task test:e2e` vide `LANDING_MEDIA_BASE_URL`, que le `.env` chargรฉ par le Taskfile pouvait faire pointer vers le vrai hรดte mรฉdia de l'opรฉrateur โ€” chaque chargement de la page d'accueil sur ordinateur diffusait alors le vrai clip pendant 15 s et le parcours de l'en-tรชte dans les six langues dรฉpassait son budget de 90 s. - Le parcours du bloc de code colorรฉ attend son rendu final : un bloc dont le langage est connu se dessine deux fois (un `
` simple le temps que le coloriseur charge, puis le sien, un nouvel รฉlรฉment), et le parcours faisait parfois dรฉfiler ou mesurait le premier (7 exรฉcutions sur 16 sous charge) ; il attend dรฉsormais les jetons Prism (64 exรฉcutions sur 64).

## [2.3.0] - 2026-10-02

**Une session Live qui se met en veille au lieu de s'arrรชter, ยซ Dis LIA ยป entendu dans le navigateur, un heartbeat qui ne s'interdit plus rien.** Un silence endort une session Live : la connexion au fournisseur se ferme, rien n'est facturรฉ, et la phrase ou un toucher la rรฉveille avec le contexte de LIA ; seule la personne termine une session. Le mot d'activation est dรฉsormais un petit modรจle entraรฎnรฉ, exรฉcutรฉ dans un worker du navigateur โ€” en bรชta et en franรงais seulement pour l'instant โ€” et ยซ Stop ยป coupe la voix de LIA. Le heartbeat รฉvalue chaque passage de sa fenรชtre sans quota quotidien, le champ destinataire d'ยซ Envoyer par e-mail ยป suggรจre tes contacts, l'alerte de connexion propose ยซ Tout reconnecter ยป, la page d'accueil gagne une vidรฉo et le blog des illustrations qui se chargent sans attendre.

### Added

- **Veille des sessions Live** ([ADR-329](docs/architecture/ADR-329-Live-Standby-And-Multilingual-Wake-Word.md)) : une session Live โ€” dรฉlรฉguรฉe ou directe, chez les trois fournisseurs โ€” s'endort aprรจs le silence de son modรจle, sur une page masquรฉe au-delร  de son dรฉlai de grรขce, ou sur le bouton de la personne. Le navigateur ferme la connexion au fournisseur (rien ne tourne ni ne se facture) puis le dรฉclare (`POST /live/sessions/{id}/standby`) ; l'enregistrement reste rรฉclamรฉ, vit jusqu'ร  `LIVE_STANDBY_MAX_SECONDS` (8 h par dรฉfaut) et passe du compte des sessions actives ร  l'ensemble `live:standby`. **Seule la personne termine une session.** Un rรฉveil (`POST โ€ฆ/wake`, la phrase ou le bouton) ouvre une NOUVELLE connexion : refus dans l'ordre (dรฉjร  รฉveillรฉe, plafond, cadence de crรฉation, plafond d'instance), setup re-rendu ร  l'instant du rรฉveil par la fonction du dรฉmarrage (`setup_render.render_setup_inputs` : horloge, รฉtat intรฉrieur, interrupteurs du moment), resynchronisation d'un agent dont les outils ont changรฉ, puis crรฉation du jeton โ€” un refus laisse la session endormie. Le plafond est dรฉcalรฉ de la durรฉe du sommeil : les dix minutes d'une session sont dix minutes ร‰VEILLร‰ES. Deux tentatives de connexion (poignรฉe de reprise, puis sans), puis retour en veille sous la raison `wake_failed`. Une session directe relaie ses รฉchanges ร  chaque mise en veille (liste des tours vidรฉe en une commande, chaque issue dans une liste ร  part) ; la carte de fin compte les veilles et cite le rรฉcapitulatif de chaque relais qui n'a pas pu s'exรฉcuter. Durรฉes, ligne de dรฉcision, histogramme et compteur du navigateur comptent le temps รฉveillรฉ ; la facture du vendeur est lue sur toutes les conversations ouvertes par la session, entiรจre ou absente. Navigateur : `LiveStandby` (`lib/live/standby.ts`), un bouton unique qui change de rรดle (le focus clavier survit), une รฉtape aprรจs chaque attente vรฉrifie que la session est toujours celle du store, et un iPhone est invitรฉ ร  garder l'รฉcran allumรฉ. Mรฉtriques `live_session_standby_total`, `live_session_wakes_total`, jauge `live_sessions_standby` (trois panneaux, tableau de bord 30).
- **Mot d'activation entraรฎnรฉ, exรฉcutรฉ dans le navigateur โ€” en bรชta, en franรงais** (ADR-329) : ยซ Dis LIA ยป est un classifieur openWakeWord (melspectrogramme et plongement partagรฉs, Apache-2.0, plus un classifieur d'environ 0,86 Mo par langue) exรฉcutรฉ par ONNX Runtime Web en WASM monothread dans un worker dรฉdiรฉ โ€” ni `SharedArrayBuffer` ni isolation inter-origines, donc aussi sur iOS et dans les coques natives. Chaque fichier est nommรฉ par son SHA-256, vรฉrifiรฉ (taille et empreinte) avant d'รชtre exรฉcutรฉ, servi `immutable` ; le manifeste de la langue dรฉcrit fichiers, politique de dรฉtection, mesures et provenance de chaque entrรฉe avec sa licence. `WAKE_MODEL_STATUS` dรฉclare les langues livrรฉes : le franรงais seul, en `beta` (son banc n'atteint pas encore les seuils publiรฉs, et le dit) ; une autre langue d'interface garde le badge au toucher et l'appui long, sans jamais demander le micro, et les rรฉglages le disent. `useVoiceMode` รฉcoute par `useWakeWord` ; `WakeListener` charge le modรจle avant d'ouvrir le micro, le libรจre en pause et passe son flux vivant ร  l'enregistrement qui suit une dรฉtection.
- **ยซ Stop ยป coupe la voix de LIA** (ADR-329) : un second classifieur sur les mรชmes plongements, dรฉclarรฉ par le manifeste sous `commands`, coupe la lecture d'une rรฉponse et rien d'autre (aucun enregistrement, aucun message). Dire ยซ Dis LIA ยป pendant que LIA parle la coupe aussi avant d'ouvrir l'enregistrement.
- **Boรฎte ร  outils d'entraรฎnement `scripts/wake-word/`** : deux images Docker รฉpinglรฉes (CPU, et GPU pour les voix VoxCPM2), positifs et quasi-homophones synthรฉtisรฉs par Piper et VoxCPM2, nรฉgatifs FLEURS, Multilingual LibriSpeech et MUSAN, chaque tรฉlรฉchargement รฉpinglรฉ par adresse immuable et SHA-256 (`sources.lock.json`), banc sur voix et corpus tenus ร  l'รฉcart (rappel au propre et ร  10/5 dB, rappel par forme รฉcrite, faux dรฉclenchements par heure sur la parole et la musique, latence) contre des seuils publiรฉs avant l'entraรฎnement. Procรฉdure : [WAKE_WORD_TRAINING.md](docs/technical/WAKE_WORD_TRAINING.md). Tรขches `wake:*`, `lint:wake` dans la CI.
- **Le champ destinataire suggรจre tes contacts** (amendement [ADR-321](docs/architecture/ADR-321-A-File-Or-An-Answer-Sent-By-E-Mail.md)) : dans tout dialogue ยซ Envoyer par e-mail ยป, taper un nom, un prรฉnom (accents et ponctuation ignorรฉs) ou un numรฉro de tรฉlรฉphone propose les contacts correspondants et insรจre leur ADRESSE. `GET /email-share/options` publie `recipient_suggestions`, `recipient_query_min_chars` et `recipient_suggestions_max` ; `GET /email-share/recipients?q=` rรฉpond pour UN destinataire, sous sa propre limite de dรฉbit. Chaque client de contacts lit le carnet entier (`list_email_directory`, paritรฉ Google/Microsoft/Apple, sous `EMAIL_SHARE_DIRECTORY_MAX_CONTACTS`, coupure dรฉclarรฉe), compactรฉ et mis en cache dans la famille dรฉclarรฉe `contacts_directory` (USER_CACHE) avec un tampon de version, construit une seule fois entre workers, invalidรฉ par toute รฉcriture de contacts ; la correspondance (`recipient_match.py`) passe par `fold_name`, `fold_email` et les variantes de numรฉro du domaine tรฉlรฉphonie. Une lecture du carnet est une consultation au registre (surface `email_share`, rien sur un succรจs de cache), comptรฉe par `email_share_recipient_directory_reads_total`. Le champ est un combobox WAI-ARIA (`RecipientCombobox`) ; ร‰chap ferme la liste avant le dialogue.
- **ยซ Tout reconnecter ยป dans l'alerte de connexion** (amendement [ADR-302](docs/architecture/ADR-302-OAuth-Grant-Par-Compte-Et-Consentement-Groupe.md)) : dรจs que deux connecteurs d'un mรชme fournisseur sont en erreur, l'alerte et la fenรชtre de reconnexion proposent le parcours groupรฉ de ยซ Mes connecteurs ยป. Le serveur dit ce qui est groupable (`bulk_reconnect_provider`, publiรฉ par la liste ET par le bilan de santรฉ) ; hook et dialogue de choix de compte sortent des rรฉglages (`hooks/useBulkReconnect.ts`, `components/connectors/BulkReconnectDialog.tsx`).
- **Table des utilisateurs de l'administration** : les 22 interrupteurs par compte en colonnes, dรฉclarรฉs une fois (`users/admin_columns.py`, ordre d'affichage, liste blanche des clรฉs de tri appliquรฉe par la route, `nulls last` puis `User.id`) ; colonnes e-mail et nom figรฉes au dรฉfilement horizontal, date d'inscription, lรฉgende repliable, en-tรชtes triables.
- **Vidรฉo de la page d'accueil** ([ADR-330](docs/architecture/ADR-330-Landing-Media-Served-Without-Runtime-Work.md)) : `LANDING_MEDIA_BASE_URL` (lu ร  la requรชte, jamais compilรฉ dans l'image) dรฉsigne le dossier d'un `manifest.json` ; sans lui, aucune section. Un seul รฉlรฉment `