- Minimal fix: prefix
site.baseurlto search result links indocs/_layouts/default.htmland Enter key navigation. - Tests added:
tests/test_search_links_baseurl.pyto lock the behavior (anchor href + Enter navigation). - CI/Deploy: Actions running; RSS smoke check passed; Pages deploy currently in progress and typically turns green within a minute after build.
Keep in mind
- Search JSON (
tools/generate_search_index.py) keepsuas path like/YYYY/MM/DD/slug.html; client JS must always prefix{{ site.baseurl }}. - Contribution policy lives in
README.mdonly (not shown on the site header).
Oct 26, 2025 — Autoposter/Git Push
- Symptom: “new posts not appearing”. Root cause was non–fast‑forward push failures in the local publish step; pushes failed so Pages didn’t deploy.
- Fix: GitHubPublisher now fetches + pull --rebase and pushes with
--force-with-leasebefore publishing. - Behavior: autoposter continues even if GitHub push fails; it now logs an error and proceeds.
Next small items (safe to batch later)
- Optional: add
/shortcut to focus the search input. - Optional: render result title instead of slug (would require adding
titleto the index).
Added tests — Oct 26, 2025
tests/test_layout_basic.py: blocks two-column grid; ensures per-post image and index link.tests/test_layout_more.py: scroll-margin rule, related block present, home image links to post, key handlers in search JS.tests/test_search_links_baseurl.py: search links prefixed with baseurl and Enter uses same.
CI — Oct 26, 2025
- Extended
rss-smoke.ymlto also curl a sample post, assert image + "View on index" are present, and verifyassets/search-index.jsonandassets/css/site.cssare reachable after a successful Pages deploy.
UX — Oct 26, 2025
- Added subtle page fade-in (0.15s) with reduced-motion guard.
- Homepage shows only the original repo slug/title inside the post content; removed the extra homepage title link above.
- Tests updated:
tests/test_title_link_to_post.pynow asserts absence of the extra title and of the hide rule.
Maintainability — Oct 26, 2025
- Extracted inline search script into
docs/assets/js/search.js(with Liquid front matter) and moved the inline RSS badge styles intosite.css. - Updated tests to read from
search.jsand assert layout references it.
Next Steps — Oct 26, 2025
- Add "/" shortcut to focus search input (tiny JS + 1 test). [Recommended]
- Render titles in search results (extend
generate_search_index.pywithtitle, adjustsearch.js; add 1–2 tests). - Add workflow
concurrencyto Deploy to avoid occasional "in progress" Pages conflicts. - Limit homepage to recent N posts and add a simple Archive page to cut initial load (keep all posts online).
- Optional: add max content width (e.g., 900px) for readability; add 1 CSS test.
Proposed Continuation — Oct 26, 2025 (later)
- Search results show titles
- Change: emit
titleintools/generate_search_index.py; render titles inassets/js/search.js. - Tests: assert
titleappears and is highlighted.
- Change: emit
- Max content width for readability
- Change:
section{max-width:900px;margin:0 auto}insite.css. - Tests: check rule presence; ensure no grid/fixed introduced.
- Change:
- Homepage limit + Archive page
- Change:
index.mdshows last 100; newarchive.mdlists all (same markup); keep all posts online for SEO. - Tests: assert Liquid
limit:exists; archive includes anchors.
- Change:
- Feed smoke: at least one
- Change: add curl/grep to
rss-smoke.yml. - Tests: optional unit asserting workflow text contains the grep.
- Change: add curl/grep to
- Tiny perceived-speed bump
- Change: add
<link rel="prefetch" href="{{ '/assets/search-index.json' | relative_url }}">on home only. - Tests: assert tag present in layout.
- Change: add
Oct 26, 2025 — Content Width Cap
- Change: added
section { max-width: 900px; }indocs/assets/css/site.cssto prevent overly wide content and reduce rare overlap with the left header on very wide viewports. - Test:
tests/test_layout_content_width.pyasserts the presence of the cap. - Rationale: minimal, no layout restructuring, keeps the theme’s default margins.
Oct 26, 2025 — Search Edge-Case Tests
- Added
tests/test_search_edge_cases_strings.pyto lock in behaviors:- Empty query clears results and returns early.
- Highlight escapes regex characters and uses .
- Multi-token split loop present; tokens length>1 to highlight.
- Enter does nothing when no results (guard present).
- Relaxed an over-strict layout assertion to allow the single absolute-position used by the dropdown. Overlap fix — Oct 26, 2025
- Removed
.wrapper { display:flex; ... }and relatedsection/footerflex rules insite.cssto restore theme layout and prevent wide-screen overlap with the left header. - Tests:
tests/test_layout_no_flex_wrapper.pyensures we don't reintroduce a flex wrapper; relaxedtest_layout_basic.pyto not require asection { ... }rule in custom CSS. CI concurrency — Oct 26, 2025 - Added workflow
concurrencyto Deploy Jekyll site:concurrency: group: pages-${{ github.ref }} cancel-in-progress: true
- Effect: ensures only one Pages deploy per branch runs at a time. If you push again while the previous deploy is still in progress, the older run gets auto-cancelled and the latest build deploys. This avoids the “deployment request failed due to in progress deployment” error we saw earlier.
- Test:
tests/test_ci_concurrency.pyasserts the guard is present. Search UX — Oct 26, 2025 - Added "/" shortcut: pressing slash focuses the search input unless typing in an input/textarea or holding Ctrl/Meta/Alt. Test:
tests/test_search_slash_focus.py.
Search tests — Oct 26, 2025
tests/test_search_ui_present.py: input, panel, placeholder, and scripts loaded.tests/test_search_js_behavior_strings.py: fetch path, fuzzysort usage, 20-result render, highlight usage, BASE concatenation.tests/test_search_index_file.py: asserts index file exists and is a JSON array.tests/test_search_index_schema.py: sample validatest,u,d,titlekeys and URL/date format.tests/test_search_js_front_matter.py: ensuressearch.jsgets Liquid front matter for baseurl injection.tests/test_layout_rss_and_related.py: checks{% feed_meta %}, RSS relative_url, and related links userelative_url. Search titles — Oct 26, 2025tools/generate_search_index.pynow emits atitlefield;assets/js/search.jsrenders titles and uses the same highlight logic.- Tests updated to assert title rendering. Index regenerated and committed.
Search ranking — Oct 26, 2025
- Replaced char-level fuzzysort call with a minimal token-AND substring scorer for more intuitive matching: split query on whitespace (len>1 tokens), require all tokens to appear in
t, and rank by earliest positions. - Keeps highlight logic; retains 20 results render. Tests updated accordingly. CI trigger scope — Oct 26, 2025
- Limited deploy triggers to site-related paths only to avoid churn on test-only commits:
docs/**,docs/_data/**, workflows file, and the two tools scripts.- Added
workflow_dispatch:for manual deploys.
- Test:
tests/test_ci_paths_filter.pyasserts paths filter and manual dispatch. Layout tweak — Oct 26, 2025 - Removed the
@ownerchip above post images to avoid implying a Twitter handle. - Test
tests/test_remove_owner_chip.pyensures the chip markup stays removed.
EU‑Compliant Analytics — Oct 26, 2025
- Options (privacy‑first, cookie‑less):
- Plausible Cloud (EU isolation) with custom‑domain proxy; or self‑host in EU.
- Umami self‑host on an EU VPS; serve script from our subdomain.
- Matomo self‑host (EU) with IP anonymization + cookieless mode.
- Pirsch/Simple Analytics (EU vendors, cookie‑less) — SaaS.
- Cloudflare Web Analytics (cookie‑less, but US vendor) — least strict option.
- Recommended: Plausible Cloud (EU isolation) via custom‑domain proxy; fallback: Umami self‑host EU.
- Minimal implementation plan:
- Add a
docs/_includes/analytics.htmlwith the vendor snippet. - Include it site‑wide via
docs/_layouts/default.html(done Oct 26, 2025). - Update privacy note to state no cookies, IP anonymized.
- Add a
Analytics changes — Oct 26, 2025
- Switched from index‑only include to layout include so posts are tracked.
- Added noscript pixel to
_includes/analytics.html. - Tests added:
tests/test_analytics_include.pyensures layout includes analytics, index does not duplicate it, and noscript pixel exists. - Duplication guard:
tests/test_analytics_no_duplicate.pyasserts the layout includes the analytics include exactly once and that the SA script/pixel only appear in the include.
"View on index" position — Oct 26, 2025
- Issue: anchor jump could land slightly off because homepage images load after the hash navigation, shifting content.
- Minimal fix: in
docs/_layouts/default.htmladd a tiny script that, onwindow.load, re-applies the hash and callsscrollIntoView()for the target id. No smooth scroll, no dependencies. - Tests added:
tests/test_view_on_index_anchor.pyensures href uses{{ '/' | relative_url }}#{{ page.date | date: '%Y-%m-%d' }}-{{ page.slug }}and index ids match{{ post.date }}-{{ post.slug }}.tests/test_view_on_index_position_js.pyasserts the presence oflocation.hash+scrollIntoViewcode.
RSS repo link — Oct 26, 2025
- Added a custom
docs/feed.xmlthat keeps Atom output but also emits a direct repository link per entry as<link rel="related" href="…" />. - Implementation: convert
post.contentto HTML viamarkdownify, split onhref="to grab the first link (the H1 repo link), and include it as the related link. - Test:
tests/test_feed_repo_link.pychecks the template containsrel="related"and the split logic strings.