编辑公共栏 / Edit board
'
diff --git a/tests/test_ascii_art.py b/tests/test_ascii_art.py
index 927870f9..4b80bd2c 100644
--- a/tests/test_ascii_art.py
+++ b/tests/test_ascii_art.py
@@ -35,3 +35,32 @@ async def test_machine_home_and_public_board_have_no_visual_payload(signed_brows
board = await http.get('/_public-board')
assert set(board.json()) == set(projection(default()))
assert 'ascii' not in board.json()
+
+
+def test_home_art_has_ordered_copy_and_a_stable_viewport():
+ page = html()
+ assert page.index('class="signal-copy"') < page.index('class="signal-stage"')
+ assert page.index('class="signal-meta"') < page.index('data-content')
+ assert page.count('class="signal-viewport"') == 1
+ assert 'data-ascii-canvas hidden aria-hidden="true"' in page
+ for piece, label in (
+ ('galaxy', 'Galaxy / 星系'),
+ ('flow', 'Flow / 信号流'),
+ ('aurora', 'Aurora / 极光'),
+ ('community', 'Shared SVG / 公共作品'),
+ ):
+ assert f'data-ascii-piece="{piece}"' in page
+ assert f'aria-label="{label}"' in page
+ assert page.count('class="ascii-piece-name"') == 4
+ assert page.count('class="ascii-piece-label"') == 4
+
+
+def test_restyled_home_keeps_shared_text_and_svg_escaped():
+ board = projection(default())
+ board['text'] = '

字符仍然是文本'
+ board['svg'] = '
'
+ page = html(board)
+ assert board['text'] not in page
+ assert '<img src=x onerror=alert(1)> 字符仍然是文本' in page
+ assert board['svg'] not in page
+ assert 'data-ascii-default="false"' in page
diff --git a/vendor/ascii/msg-entry.ts b/vendor/ascii/msg-entry.ts
index 71bf130b..4131e1a6 100644
--- a/vendor/ascii/msg-entry.ts
+++ b/vendor/ascii/msg-entry.ts
@@ -64,6 +64,10 @@ function attach(surface: HTMLElement) {
if ((event as CustomEvent).detail.svgChanged) choose('community');
});
if (pause) new MutationObserver(play).observe(pause, {attributes: true, attributeFilter: ['aria-pressed']});
+ // A paused canvas still needs a new ink color when the reader changes theme.
+ // Restarting the renderer preserves elapsed scene time and its pause/motion gates.
+ new MutationObserver(play).observe(document.documentElement, {attributes: true, attributeFilter: ['data-theme']});
+ matchMedia('(prefers-color-scheme: dark)').addEventListener('change', play);
surface.dataset.asciiReady = 'true';
if (controls) controls.hidden = false;
choose(name);
From 05cfb2f88c9ad57f5034429f005866d0db1a124d Mon Sep 17 00:00:00 2001
From: LIghtJUNction
Date: Mon, 12 Oct 2026 07:09:19 +0800
Subject: [PATCH 2/2] test: keep ASCII home layout and interaction checks in
browser CI
---
.github/workflows/home-first-read.yml | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/home-first-read.yml b/.github/workflows/home-first-read.yml
index 40258d6d..f481c770 100644
--- a/.github/workflows/home-first-read.yml
+++ b/.github/workflows/home-first-read.yml
@@ -8,6 +8,10 @@ on:
- 'tests/test_browser*'
- 'tests/test_thread*'
- 'scripts/check_home_first_read_browser.py'
+ - 'scripts/check_ascii_home_browser.py'
+ - 'src/msg/data/ascii-runtime.js'
+ - 'vendor/ascii/**'
+ - 'tests/test_ascii_art.py'
- '.github/workflows/home-first-read.yml'
push:
branches: [main]
@@ -18,6 +22,10 @@ on:
- 'tests/test_browser*'
- 'tests/test_thread*'
- 'scripts/check_home_first_read_browser.py'
+ - 'scripts/check_ascii_home_browser.py'
+ - 'src/msg/data/ascii-runtime.js'
+ - 'vendor/ascii/**'
+ - 'tests/test_ascii_art.py'
- '.github/workflows/home-first-read.yml'
workflow_dispatch:
permissions:
@@ -50,6 +58,13 @@ jobs:
with:
python-version: '3.15'
allow-prereleases: true
+ - uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: '1.4.0'
+ - name: Verify the committed ASCII runtime matches its source
+ run: |
+ bun scripts/build_ascii.mjs
+ git diff --exit-code -- src/msg/data/ascii-runtime.js
- name: Install test tools
run: |
sudo apt-get update -qq
@@ -60,15 +75,17 @@ jobs:
- name: Verify first reads, authority and existing browser routes
run: |
mkdir -p artifacts
- uv run pytest tests/test_home_first_read.py tests/test_home_cache.py tests/test_browser_refinement.py tests/test_browser_html.py tests/test_browser_languages.py tests/test_thread_panel.py tests/test_thread_panel_http.py tests/test_board_presentation.py --junitxml=artifacts/browser-first-read-tests.xml
+ uv run pytest tests/test_home_first_read.py tests/test_home_cache.py tests/test_browser_refinement.py tests/test_browser_html.py tests/test_browser_languages.py tests/test_thread_panel.py tests/test_thread_panel_http.py tests/test_board_presentation.py tests/test_ascii_art.py tests/test_public_board.py tests/test_public_board_details.py --junitxml=artifacts/browser-first-read-tests.xml
- name: Verify real navigation and responsive rendering under CSP
env:
PYTHONPATH: src
- run: uv run python scripts/check_home_first_read_browser.py
+ run: |
+ uv run python scripts/check_home_first_read_browser.py
+ uv run python scripts/check_ascii_home_browser.py
- name: Check changed source and tests
run: |
- uv run ruff check src/msg/transports/{browser_style,home_page,http_routes,thread_browser}.py tests/{test_home_first_read,test_browser_refinement,test_thread_panel}.py scripts/check_home_first_read_browser.py
- uv run ruff format --check src/msg/transports/{browser_style,home_page,http_routes,thread_browser}.py tests/{test_home_first_read,test_browser_refinement,test_thread_panel}.py scripts/check_home_first_read_browser.py
+ uv run ruff check src/msg/transports/{ascii_art,public_board,browser_style,home_page,http_routes,thread_browser}.py tests/{test_ascii_art,test_home_first_read,test_browser_refinement,test_thread_panel}.py scripts/check_home_first_read_browser.py scripts/check_ascii_home_browser.py
+ uv run ruff format --check src/msg/transports/{ascii_art,public_board,browser_style,home_page,http_routes,thread_browser}.py tests/{test_ascii_art,test_home_first_read,test_browser_refinement,test_thread_panel}.py scripts/check_home_first_read_browser.py scripts/check_ascii_home_browser.py
uv run python -W error -m compileall -q src
git diff --check
- uses: actions/upload-artifact@v7.0.1