Skip to content

chore: simplify escaping and release 0.5.0 - #42

Merged
geoqiao merged 20 commits into
mainfrom
chore/simplify-0.5
Sep 29, 2026
Merged

geoqiao merged 20 commits into
mainfrom
chore/simplify-0.5

Conversation

@geoqiao

@geoqiao geoqiao commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

问题与改动

仓库变臃肿了:同一件事有多处实现,有的代码没人用,测试钉死了 Quiet 的具体尺寸和颜色,文档重复,依赖和 Action 版本也旧了。这个 PR 做减法,Config 用法不变,站点输出除 Mermaid 升级和 sitemap 里几条 URL 的顺序外不变(例外见“风险与兼容性”)。

  • 代码
    • Atom feed 直接从 SiteModel 渲染,删掉中间模型和一整套单测(atom_feed.py 478 → 约 70 行)。站点标题、作者、描述里有 XML 不允许的字符,现在在读 Issue 之前就报 Config 错误。
    • Blog 分页和标签并进 SiteBuilder;Blog 和 Ideas 只在 ContentCompiler 排一次序,其他地方不再各排一遍。
    • slug 规则只剩一份;保留 slug page 的检查和其他内容规则放在一起。
    • 输出替换(output staging)缩短约 120 行,检查项不变。
    • 用标准库 logging 取代 structlog,少一个依赖。
    • 删掉 0.2/0.3 旧字段的迁移提示和没人用的代码。
  • 修复
    • 一篇 Blog 含 XML 不允许的字符时只跳过这一篇(原来整站失败)。
    • 继承 Quiet 的 Theme 去掉暗色按钮后,目录和复制代码按钮不再消失。
  • Quiet:标题字体改用 31 KB 的 woff2(原来 95 KB 的 TTF),删掉没用到的 Source Serif 4(194 KB)和无效 CSS。
  • 测试:浏览器测试不再钉死像素和颜色,只查功能和可用性(键盘可达、不溢出、不重叠、焦点可见);Issue 转换改用真实 PyGithub 对象,不再用 mock。
  • 文档:升级只剩一条路径;Theme 迁移合成一节;测试规则只在 docs/agents/testing.md 一处。
  • 版本
    • CI:checkout 7.0.1、setup-python 7.0.0、setup-uv 10.2.0。
    • Action 和 CI 用 uv 0.12.17:这是 setup-uv 10.2.0 能校验下载的最新版本(0.12.19 会跳过校验)。
    • Mermaid 11.17.2(12.0 是大版本,暂不升);Pygments 2.21.0,重新生成的高亮颜色完全相同;其余依赖升到最新。
    • starter 用 deploy-pages 5.0.1。
  • 版本号 0.5.0,CHANGELOG 已写。

不在范围内:新功能、Theme API 变化、Mermaid 12。

验证结果

  • 本地完整检查(uv lock --check、CI=true uv run pytest -q -ra、ruff check、ruff format --check、ty check、整个分支的 git diff --check):693 passed,无跳过,全部通过。测试数比 main 少,是因为删了重复和基于 mock 的测试。
  • Atom 输出在重写前后逐字节相同。
  • 每个重构提交都单独跑过完整检查。
  • 用真实站点 geoqiao.me(origin/main、同一份 79 个 Issue、同一份 context)分别以 v0.4.0 和本分支构建:两次都成功、无跳过;170 个文件中 167 个逐字节相同。不同的 3 个:Mermaid 的 bundle 和它的 README(预期),以及 sitemap.xml——81 个 URL 完全相同,只是 Blog 分页的 3 个 URL 排到了 Projects 后面(分页并进 SiteBuilder 后注册顺序变了;sitemap 的顺序没有含义)。
  • 真实文章里的 Mermaid 图(3 篇、5 张)在 Chromium 和 WebKit、亮色和暗色下都渲染出来了。WebKit 报的 TypeError: Load failed 在 v0.4.0 的产物上一模一样,不是这次引入的。

风险与兼容性

  • 继承 Quiet 且链接了 manrope-bold.ttf 或 source-serif-4.ttf 的 Theme 需要自带这两个文件。

  • 旧字段(0.2/0.3 之前的写法)现在报“未知字段”,不再提示新位置;在 0.4.0 上它们本来就会报错,能正常构建的站点不受影响。

  • 进度日志改成 stderr 上的普通文本行。

  • 回滚:站点把 pin 改回 @v0.4.0。

  • 已遵循维护指南与测试策略,说明适用检查的实际结果

  • 未弱化内容授权、sanitizer、路径 containment、artifact validation 或失败保旧产物

  • 公共行为变化已同步契约与迁移说明;远程发布或站点变更有单独授权(如适用)

🤖 Generated with Claude Code

geoqiao and others added 20 commits September 28, 2026 22:26
A character that XML 1.0 forbids, such as U+0001, in a Blog post's title,
body or description used to fail the whole build when the Atom feed was
written. The shared content rules now reject it for that post, so the
post is skipped (exit code 2) and the draft lint reports it too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Theme that extends Quiet may replace header.html without the
appearance button. site.js then threw before it built the table of
contents and the copy-code buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A live site builds with the 0.4.0 Action; a repository made from the
template has not been tried end to end yet. escaping-template now
matches starter/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- AGENTS.md: Themes can come from GitHub and extends can name one;
  templates run in Jinja's sandbox; the file list matches src/.
- Issue content contract: a bad Blog or Idea Issue is skipped, not a
  failed build; the oldest About wins; tag keys may be Unicode; paths
  are defaults that pages can move.
- ADR 0007 and 0008 say which later ADRs amend them.
- The draft docs agree with the code: the Issue body always has a front
  matter block. The lint skill names /assets/.
- testing.md lists the remote Theme, Atom and draft test owners and
  drops the finished rebuild plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Source Serif 4 and --serif were left behind when the post body moved
  to the sans stack; browsers never downloaded the font.
- Manrope ships as WOFF2 (31 KB) instead of TTF (95 KB); same glyphs.
- Remove declarations that repeat inherited or global values or can never
  apply: text-decoration: none on links (the global a rule has it), a
  hover colour equal to a:hover, color: inherit on a span, a max-width
  wider than <main>, and a checkbox rule the sanitizer makes unreachable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ThemeConfig.local_path and RouteRegistry.route_for_url had only tests
  as callers.
- parse_front_matter's raising mode for unknown fields: the compiler
  always collects them and reports each one.
- SiteCompiler(output_staging=...) was never passed.
- OptionSpec copied the theme.yaml option model field by field; the
  model is now OptionSpec.
- RouteRegistry rejected .html in page paths, which every path
  validator already rules out; the output path check stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Old Config fields and a theme.yaml pages: key are now plain unknown
fields, and an old Theme API gets the one api: 4 message. The Theme
guide keeps the tables of where each setting went.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.gitignore was the generic Python template plus old site paths; the
short version ignores the same files in this checkout. The independent
test Theme never used mark.svg.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The feed builder re-checked every post for timestamps without a time zone
and for characters XML forbids, and the renderer checked again. Blog posts
are already checked when they are read, so the feed is now one function
that renders the SiteModel, with the same bytes as before. The remaining
checks moved to where the text comes in: the site title, author and
description are checked with the Config, and an Issue time without a zone
is refused when the Issue is read. The renderer still refuses to write a
feed XML cannot parse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Blog archive and the tag pages were each a module plus a model module,
and the tag result carried a diagnostics list that was always empty. They
are now two functions in site_builder.py, and ArchivePage and Tag live with
the rest of the SiteModel. ArchivePage loses two URL properties nothing
read; Tag keeps them, since Themes use them.

The ContentCompiler already sorts Blog posts and Ideas newest first, so the
archive, tags, feed, search index and render context stop sorting them
again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rest

Blog and project slugs were checked by three copies of the same pattern;
routes.SLUG is now the only one. The reserved Blog slug "page" was checked
separately by the ContentCompiler and the local draft check; it is now part
of the shared content rules, with the same error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The module described publication four times over, in the module, class and
method docstrings. It now says it once. Four one-line wrappers around the
ownership check and the registries are gone; every path is still checked
before it is renamed or deleted, with the same errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
structlog was used for five lines, printed to stdout next to the GitHub
Actions annotations, and three of them repeated an error or warning the
build already reports. Those three are gone. The downloaded Theme's commit
and the traceback of an unexpected crash now go through logging, which the
escpe command prints to stderr as plain lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Quiet's widths, font sizes, line heights, borders and palette were each
asserted to the pixel or the RGB value, so any restyle failed the suite
without anything being broken. Those assertions are gone. The tests still
check what a reader relies on: pages stay centered and do not overflow or
overlap, controls are large enough and show focus, the layout does not
shift when scripts load, Mermaid text keeps its contrast, reduced motion
stops movement, and code keeps its text and scrolls.

The two browser launches now share one helper, and the fixture that runs a
test in both Chromium and WebKit is named for that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two tests built Issues out of MagicMock and mostly checked the mocks: that
no field was a MagicMock and that no mocked write method was called. The
test with real PyGithub objects now compares the whole snapshot, and the
local GitHub stand-in, which answers only GET, already fails any write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge the API 3 and API 2 migration notes into one table set that maps
straight to API 4, point every link at it, and give the README a single
upgrade path. Drop the claim that old 0.1 fields tell you where they
moved; since the hints were removed they are reported as unknown fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md now points to the testing guide instead of repeating its test
budget. The guide folds the "minimum set" list into the budget, the
domain doc drops advice for files that already exist, and the build
diagram shows that the SiteBuilder now pages the Blog and builds tags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CI: checkout 7.0.1, setup-python 7.0.0, setup-uv 10.2.0.
- Action and CI: uv 0.12.17, the newest release setup-uv 10.2.0 has a
  checksum for, so the download is still verified.
- Starter: deploy-pages 5.0.1.
- Mermaid 11.17.2 from the npm package (integrity checked); 12.0 is a new
  major and waits. .gitattributes still named the bundle's pre-0.2 path;
  it now marks the current file binary, so whitespace checks skip it.
- Pygments 2.21.0: the regenerated token rules are identical, so only the
  header of syntax.css changes.
- uv lock --upgrade. ty 0.0.84 could not infer the sort key lambda in
  _newest_first, so it uses attrgetter; one ty: ignore is no longer needed.
- Drop the ruff ignore for the deleted tests/test_atom_feed.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@geoqiao
geoqiao merged commit 95c53c9 into main Sep 29, 2026
1 check passed
@geoqiao
geoqiao deleted the chore/simplify-0.5 branch September 29, 2026 03:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant