From 137817e2b04264f2f1842c199157aab871989979 Mon Sep 17 00:00:00 2001 From: Ori Nachum Date: Wed, 22 Jul 2026 19:11:40 +0300 Subject: [PATCH 1/2] fix(deck): move the closing footer to the finale, the deck's last slide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "full argument, in text" CTA, the all-presentations link, and the subordinate Sources disclosure sat on slide 6 (close) — where the deck used to end. With the whats-next finale as slide 7, the deck's closing chrome now lives there, so a viewer reaches it at the actual end. The .slide--close padding-bottom that reserved room for the fixed pager chrome beneath the sources moves to .slide--next with the footer. check-presentations pins the new location (article CTA and all-presentations link inside the finale, Sources rendered exactly once deck-wide and inside the finale) — the CTA assertion was observed failing against the pre-move build. Dataset prose updated: deckSources renders once in the finale's footer, not on the close slide. Verified: 20/20 node tests, astro build clean, 23/23 presentation checks, 56 pytest, markdownlint clean, both slides screenshot-reviewed. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01FqTq59W6wi1YZqxGf228Tt --- CHANGELOG.md | 6 ++ pyproject.toml | 2 +- site-astro/scripts/check-presentations.mjs | 22 ++++++ .../data/mind-nervous-system-body-slides.ts | 5 +- .../mind-nervous-system-body.astro | 68 ++++++++++--------- uv.lock | 2 +- 6 files changed, 69 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ff798f..9d2ebee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. Format follows [Keep a Changelog](https://keepachangelog.com/). This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.18.1] - 2026-07-22 + +### Changed + +- The deck's closing footer — the "full argument, in text" CTA, the all-presentations link, and the subordinate Sources disclosure — moved from slide 6 (close) to slide 7 (the whats-next finale), so it sits on the deck's actual last slide; the fixed-chrome padding follows it, and check-presentations pins the new location. + ## [0.18.0] - 2026-07-22 ### Added diff --git a/pyproject.toml b/pyproject.toml index 3ffef3a..a7f11ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "org" -version = "0.18.0" +version = "0.18.1" description = "The AgentCulture org site — source of the web presence published to AgentCulture.org. Replaces the deleted landing-page repo. Not distributed on PyPI: the CLI stays repo-local; the deliverable is the published site." readme = "README.md" license = "Apache-2.0" diff --git a/site-astro/scripts/check-presentations.mjs b/site-astro/scripts/check-presentations.mjs index a0589d1..8f1c0e8 100644 --- a/site-astro/scripts/check-presentations.mjs +++ b/site-astro/scripts/check-presentations.mjs @@ -673,6 +673,28 @@ check("deck finale: whats-next is last with the triad, separation band, no photo finale.attrs["data-robot"] === undefined, "finale section must carry no data-robot attribute", ); + + // The deck's closing footer (article CTA, all-presentations link, the + // subordinate Sources disclosure) sits on the LAST slide — it moved off + // the close slide when the finale became slide 7. + assert( + linksTo(finale.inner, articleRoute).length === 1, + `the finale must carry the article CTA (${articleRoute}) exactly once`, + ); + assert( + linksTo(finale.inner, presentationsRoute).length >= 1, + `the finale must carry the all-presentations link (${presentationsRoute})`, + ); + const finaleSources = countOccurrences(finale.inner, ">Sources"); // scope-attr safe + assert( + finaleSources === 1, + `the Sources disclosure must render exactly once, on the finale; found ${finaleSources} there`, + ); + const deckSourcesTotal = countOccurrences(deckHtml, ">Sources"); + assert( + deckSourcesTotal === 1, + `the deck must render exactly one Sources disclosure, found ${deckSourcesTotal}`, + ); }); check("deck imagery: three robot photos with alt text", () => { diff --git a/site-astro/src/data/mind-nervous-system-body-slides.ts b/site-astro/src/data/mind-nervous-system-body-slides.ts index 85ce539..7e772b2 100644 --- a/site-astro/src/data/mind-nervous-system-body-slides.ts +++ b/site-astro/src/data/mind-nervous-system-body-slides.ts @@ -11,7 +11,8 @@ // evidence-pinned beat text stay put in `mind-nervous-system-body.ts`; this // module still does not derive from it and carries no per-slide evidence // ids. Sources stay subordinate: see `deckSources` below (repo homes + one -// dated note), rendered once on the close slide, never per-slide. +// dated note), rendered once in the deck's closing footer on the finale +// slide, never per-slide. // // DECK SHAPE — exactly seven slides, one per primary beat (`beat` 1-7, in // slide order): org#23's six plus the whats-next-finale-slide trajectory @@ -328,7 +329,7 @@ export interface DeckSourceProject { } /** - * The deck's subordinate sources note, rendered once on the close slide (not + * The deck's subordinate sources note, rendered once on the finale slide (not * per-slide): repo-home links for both projects plus one dated note. This is * the deck's evidence surface — the article keeps the strict, commit-pinned * ledger in `presentations.ts` / `mind-nervous-system-body.ts`, untouched. diff --git a/site-astro/src/pages/presentations/mind-nervous-system-body.astro b/site-astro/src/pages/presentations/mind-nervous-system-body.astro index fe2f78d..5c5f08b 100644 --- a/site-astro/src/pages/presentations/mind-nervous-system-body.astro +++ b/site-astro/src/pages/presentations/mind-nervous-system-body.astro @@ -15,10 +15,13 @@ // 4. surfaces — the reachy-mini-action photo with three labels around it. // 5. autonomy — a triptych of three DeckSituationVignettes (stuck, // disconnected, routine); no photo. -// 6. close — two dual-maturity robot cards, the verbatim thesis, sources. +// 6. close — two dual-maturity robot cards and the verbatim thesis. // 7. whats-next — the trajectory finale: See/Remember/Act glyph triad, two // next-step cards (no photos, no data-robot), the shared -// separation band, the six-sentence spoken close. +// separation band, the six-sentence spoken close, and the +// deck's closing footer (article CTA, all-presentations link, +// the subordinate Sources disclosure) — it sits on the last +// slide, so it moved off "close" when the finale landed. // // Navigation is progressive enhancement over natural scroll: the dot rail is // plain anchors, the prev/next chrome and keyboard support exist only under @@ -390,34 +393,6 @@ const slideViews = slides.map((slide, index) => {

{slide.bottomLine}

-
- -
- Sources - -

{deckSources.note}

-
-
)} @@ -478,6 +453,34 @@ const slideViews = slides.map((slide, index) => { > {slide.spokenLine}

+
+ +
+ Sources + +

{deckSources.note}

+
+
)} @@ -1041,8 +1044,9 @@ const slideViews = slides.map((slide, index) => { color: var(--accent-strong); } - .slide--close { - /* room for the fixed chrome beneath the sources on short viewports */ + .slide--next { + /* room for the fixed chrome beneath the sources on short viewports — + the closing footer moved here when the finale became the last slide */ padding-bottom: 7rem; } diff --git a/uv.lock b/uv.lock index 1740f40..4327dba 100644 --- a/uv.lock +++ b/uv.lock @@ -236,7 +236,7 @@ wheels = [ [[package]] name = "org" -version = "0.18.0" +version = "0.18.1" source = { editable = "." } [package.dev-dependencies] From c9d00922de85a9f6c500021d5f6652ad8dd6b9a4 Mon Sep 17 00:00:00 2001 From: Ori Nachum Date: Wed, 22 Jul 2026 19:36:32 +0300 Subject: [PATCH 2/2] test(site): tighten and de-brittle the finale footer checks (Qodo review) Two fixes to the finale check this PR added, both from Qodo on #28: - the all-presentations link asserted >= 1, so duplicate footer rendering would still pass while the article CTA next to it required exactly one. Now === 1, with the found count in both messages. - the Sources uniqueness assertions counted the raw substring ">Sources", which a harmless whitespace or formatting change in the rendered markup would break. Replaced with a semantic countSourcesSummaries() built on the existing elements() + textContent() helpers. Both verified against the built HTML: injecting a second /presentations/ link into the finale fails the tightened assertion, and reformatting the summary across newlines still passes 23/23 where the old substring count would have read 0. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01FqTq59W6wi1YZqxGf228Tt --- site-astro/scripts/check-presentations.mjs | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/site-astro/scripts/check-presentations.mjs b/site-astro/scripts/check-presentations.mjs index 8f1c0e8..e58a408 100644 --- a/site-astro/scripts/check-presentations.mjs +++ b/site-astro/scripts/check-presentations.mjs @@ -197,6 +197,16 @@ function linksTo(html, href) { return anchors(html).filter((anchor) => anchor.attrs.href === href); } +/** Count semantic Sources disclosures. Element-based rather + * than a raw-substring count, so Astro's scope attributes and any harmless + * whitespace/formatting change in the rendered markup can't cause a false + * failure (PR #28 review). */ +function countSourcesSummaries(html) { + return elements(html, "summary").filter( + (summary) => textContent(summary.inner) === "Sources", + ).length; +} + function countOccurrences(html, needle) { return (html.match(new RegExp(needle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g")) ?? []) .length; @@ -677,20 +687,22 @@ check("deck finale: whats-next is last with the triad, separation band, no photo // The deck's closing footer (article CTA, all-presentations link, the // subordinate Sources disclosure) sits on the LAST slide — it moved off // the close slide when the finale became slide 7. + const finaleArticleLinks = linksTo(finale.inner, articleRoute).length; assert( - linksTo(finale.inner, articleRoute).length === 1, - `the finale must carry the article CTA (${articleRoute}) exactly once`, + finaleArticleLinks === 1, + `the finale must carry the article CTA (${articleRoute}) exactly once; found ${finaleArticleLinks}`, ); + const finalePresentationsLinks = linksTo(finale.inner, presentationsRoute).length; assert( - linksTo(finale.inner, presentationsRoute).length >= 1, - `the finale must carry the all-presentations link (${presentationsRoute})`, + finalePresentationsLinks === 1, + `the finale must carry the all-presentations link (${presentationsRoute}) exactly once; found ${finalePresentationsLinks}`, ); - const finaleSources = countOccurrences(finale.inner, ">Sources"); // scope-attr safe + const finaleSources = countSourcesSummaries(finale.inner); assert( finaleSources === 1, `the Sources disclosure must render exactly once, on the finale; found ${finaleSources} there`, ); - const deckSourcesTotal = countOccurrences(deckHtml, ">Sources"); + const deckSourcesTotal = countSourcesSummaries(deckHtml); assert( deckSourcesTotal === 1, `the deck must render exactly one Sources disclosure, found ${deckSourcesTotal}`,