fix(web): gate welcome-hero footnotes on instance.overview flag

Bring the original Overview gating contract forward to the new
footnotes block: any non-empty `instance.overview` /
AGNES_INSTANCE_OVERVIEW value enables the footnotes, an empty
value hides them. The raw yaml HTML body is no longer rendered
(the static product framing replaces it) — operators relying on
custom Overview HTML should migrate that content to
instance.custom_scripts or admin-edited news.

Preserves the explanatory comments from the original Overview
section (operator-owned, opt-in, no dismiss button) so future
readers understand why the block is gated.

Splits the test into two halves matching the original gating
pattern: footnotes appear when the flag is set, hidden when
unset. Uses "Get the most out of it" as the marker (unique to
the footnotes copy) since "What leaves your machine" still
appears in the untouched session-privacy annotation lower on
the page.
This commit is contained in:
David Rybar 2026-05-22 11:35:40 +02:00
parent 61262e2bbb
commit 2db1dceca1
3 changed files with 73 additions and 15 deletions

View file

@ -47,9 +47,13 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
stays local, `/agnes-private` toggles per-session) and the stays local, `/agnes-private` toggles per-session) and the
workspace-layout convention (*"Get the most out of it"* — work workspace-layout convention (*"Get the most out of it"* — work
under `~/<workspace_dir>/Projects/`, anything outside the under `~/<workspace_dir>/Projects/`, anything outside the
workspace root is invisible to the platform). Renders for both workspace root is invisible to the platform). Gated on the same
onboarded and not-onboarded users so the operating model is `instance.overview` / `AGNES_INSTANCE_OVERVIEW` flag that used
visible on every visit. to drive the standalone Overview section — any non-empty value
acts as the feature flag — so the OSS keeps a vendor-neutral
default (empty yaml → footnotes absent) while operators who
flip the flag get a consistent message across instances.
Renders for both onboarded and not-onboarded users.
- Welcome hero's *"AI Chief of Staff"* lede gains a trailing - Welcome hero's *"AI Chief of Staff"* lede gains a trailing
sentence ("*You run all your projects inside and it learns sentence ("*You run all your projects inside and it learns
from it.*") so the workspace-folder framing lands before the from it.*") so the workspace-folder framing lands before the
@ -259,11 +263,13 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
`instance.overview` / `AGNES_INSTANCE_OVERVIEW` HTML body between `instance.overview` / `AGNES_INSTANCE_OVERVIEW` HTML body between
the first-session walkthrough and the surfaces grid). The the first-session walkthrough and the surfaces grid). The
privacy-posture / workspace-layout copy it carried now ships privacy-posture / workspace-layout copy it carried now ships
inline in the welcome hero footnotes, so a separate operator inline in the welcome hero footnotes (see *Changed* above). The
surface for the same content is no longer needed. The `get_instance_overview()` helper and yaml field still drive the
`get_instance_overview()` helper and yaml field remain (harmless feature flag for the new footnotes block, but the raw HTML body
if set; just not rendered) so existing instances that override the operator stored there is no longer rendered (the static
it don't trip on a removed config key. product framing replaces it) — operators who relied on injecting
custom Overview HTML should migrate that content to
`instance.custom_scripts` or admin-edited news.
### Removed ### Removed

View file

@ -2289,6 +2289,25 @@
<p>Shared analyst knowledge and prior solutions, fed back into Claude's context on demand.</p> <p>Shared analyst knowledge and prior solutions, fed back into Claude's context on demand.</p>
</div> </div>
</div> </div>
{# Welcome-hero footnotes — operator-owned, opt-in. Gated on
the same `instance.overview` yaml field
(`AGNES_INSTANCE_OVERVIEW` env override) that used to
drive the standalone Overview section: any non-empty
value acts as the feature flag. The body itself is no
longer the operator's raw HTML — it's the canonical
product framing (privacy posture + workspace convention)
baked into the template, so the OSS keeps a
vendor-neutral default (empty yaml → footnotes absent)
while operators who flip the flag get a consistent
message across instances. #}
{# Footnotes are operator-owned reference content, not
per-user chrome — no dismiss button on purpose. A
one-time per-device hide would leave returning users
unable to re-read the privacy posture / workspace
convention without clearing localStorage. The whole
block is opt-in at the operator level (empty yaml →
block absent), which is the right axis of control. #}
{% if config.INSTANCE_OVERVIEW %}
<div class="home-hero-footnotes"> <div class="home-hero-footnotes">
<p> <p>
<strong>What leaves your machine.</strong> Session telemetry &mdash; prompts, tool calls, <strong>What leaves your machine.</strong> Session telemetry &mdash; prompts, tool calls,
@ -2306,6 +2325,7 @@
Anything outside <code>~/{{ workspace_dir }}/</code> is invisible to the platform. Anything outside <code>~/{{ workspace_dir }}/</code> is invisible to the platform.
</p> </p>
</div> </div>
{% endif %}
</section> </section>
{# Homepage status frame — five counters with 24h/7d toggle. {# Homepage status frame — five counters with 24h/7d toggle.

View file

@ -359,13 +359,17 @@ def test_setup_section_renders_for_not_onboarded(fresh_db):
assert '<div class="setup-section-header"' not in body2 assert '<div class="setup-section-header"' not in body2
def test_overview_section_never_renders(fresh_db, monkeypatch): def test_overview_section_replaced_by_welcome_footnotes(fresh_db, monkeypatch):
"""The operator-owned Overview `<section>` was removed from """The standalone operator-owned Overview `<section>` was removed
`/home` its privacy / workspace-layout copy now ships inline from `/home`. Its privacy / workspace-layout copy now ships as
in the welcome hero footnotes. The `get_instance_overview()` static product framing inside the welcome hero footnotes
helper and `instance.overview` yaml field still exist (to avoid (`.home-hero-footnotes`). The `instance.overview` yaml field
breaking instances that override them), but the rendered (`AGNES_INSTANCE_OVERVIEW`) keeps its gating role any
section MUST NOT appear regardless of the env value.""" non-empty value acts as the feature flag but its raw HTML
body is no longer rendered (the static copy replaces it). When
set: the standalone section MUST stay absent and the
footnotes block MUST appear, but the raw yaml HTML body MUST
NOT leak into the page."""
monkeypatch.setenv("AGNES_INSTANCE_OVERVIEW", "<p>OVERVIEW_TEST_MARKER</p>") monkeypatch.setenv("AGNES_INSTANCE_OVERVIEW", "<p>OVERVIEW_TEST_MARKER</p>")
from src.db import get_system_db, close_system_db from src.db import get_system_db, close_system_db
@ -378,3 +382,31 @@ def test_overview_section_never_renders(fresh_db, monkeypatch):
body = _client().get("/home", cookies={"access_token": sess}).text body = _client().get("/home", cookies={"access_token": sess}).text
assert '<section class="home-overview">' not in body assert '<section class="home-overview">' not in body
assert "OVERVIEW_TEST_MARKER" not in body assert "OVERVIEW_TEST_MARKER" not in body
assert '<div class="home-hero-footnotes">' in body
# "Get the most out of it" is unique to the footnotes block — the
# original "What leaves your machine" copy still exists in the
# session-privacy annotation lower on the page (untouched), so we
# can't use it as a footnotes marker.
assert "Get the most out of it" in body
def test_welcome_footnotes_hidden_when_overview_unset(fresh_db, monkeypatch):
"""Default empty `instance.overview` (no env override) hides the
welcome-hero footnotes entirely so the OSS ships without the
central-catalog privacy framing baked into the welcome card."""
monkeypatch.delenv("AGNES_INSTANCE_OVERVIEW", raising=False)
from src.db import get_system_db, close_system_db
conn = get_system_db()
try:
_, sess = _make_user_and_session(conn)
finally:
conn.close()
close_system_db()
body = _client().get("/home", cookies={"access_token": sess}).text
assert '<div class="home-hero-footnotes">' not in body
# "Get the most out of it" is the unique footnotes marker — the
# original "What leaves your machine" copy in the session-privacy
# annotation lower on the page always renders, so checking that
# would be a false-positive.
assert "Get the most out of it" not in body