From 5365f2373397369adb128916d05852ab512bd97f Mon Sep 17 00:00:00 2001 From: AlbertXXuu Date: Fri, 4 Sep 2026 23:48:25 +0800 Subject: [PATCH] Make the AlvenX header return to top without changing Demo state --- AGENTS.md | 5 +++ docs/assets/alvenx-ui.css | 19 ++++++++++ docs/assets/provenance.json | 5 +-- docs/brand.md | 8 +++++ harness/context/03-brand-verifiable-demo.md | 28 +++++++++++++++ plans/03-brand-verifiable-demo.md | 15 ++++++++ scripts/verify-brand.mjs | 2 ++ src/demo/public/app.js | 9 +++++ src/demo/public/index.html | 2 +- tests/playwright/demo.spec.ts | 40 ++++++++++++++++++++- 10 files changed, 129 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 62fe37a..c04b104 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,6 +98,11 @@ Run `pnpm brand:verify` (included in `pnpm check`/CI). In the AlvenX workspace a Visual changes require actual 390/900/1440px browser and resource-loading checks, comparison of computed header geometry to an accepted Studio, and independent checkout verification. +The AlvenX wordmark is a native `data-alvenx-home` button with an accessible Back to top name. +Apply home-navigation revision 2026-09-04.1 from the shared interface contract: true document top, +no action when already at the top, preserved URL/history and product state, native keyboard +activation, visible focus and immediate scrolling under reduced motion. + ## Testing standards Use the layers needed by the phase: diff --git a/docs/assets/alvenx-ui.css b/docs/assets/alvenx-ui.css index 2e97927..e1bb94c 100644 --- a/docs/assets/alvenx-ui.css +++ b/docs/assets/alvenx-ui.css @@ -115,6 +115,25 @@ height: auto; } +/* Header home-navigation revision: 2026-09-04.1 */ +.ax-product-header [data-alvenx-home] { + display: flex; + align-items: center; + flex: 0 0 auto; + width: var(--ax-product-header-wordmark-width); + min-height: var(--ax-control-height); + padding: 0; + border: 0; + border-radius: 12px; + background: transparent; + cursor: pointer; +} + +.ax-product-header [data-alvenx-home]:focus-visible { + outline: 3px solid rgb(37 99 235 / 45%); + outline-offset: 4px; +} + .ax-metric-frame { border: 1px solid var(--ax-rule); } diff --git a/docs/assets/provenance.json b/docs/assets/provenance.json index 99a0f96..eb88e8f 100644 --- a/docs/assets/provenance.json +++ b/docs/assets/provenance.json @@ -17,7 +17,7 @@ { "path": "docs/assets/alvenx-ui.css", "source": "foundation/brand/interface/alvenx-ui.css", - "sha256": "7b94510cfa9fe9eebe452481f967a9482809c5158a326842971e1d457f86daf6" + "sha256": "b4bc3051213c2d9a1a37af80233d0b4978941d73c5945f6a792b84271e1d5c0c" }, { "path": "docs/assets/InstrumentSans-wdth-wght.woff2", @@ -30,5 +30,6 @@ "sha256": "bc29b497c4e8316b2d248322a9cea670c2f0afc24ae0eb7bbaa54e02e00eebab" } ], - "wordmarkAlignmentRevision": "2026-09-04.1" + "wordmarkAlignmentRevision": "2026-09-04.1", + "homeNavigationRevision": "2026-09-04.1" } diff --git a/docs/brand.md b/docs/brand.md index 605d233..c87db7f 100644 --- a/docs/brand.md +++ b/docs/brand.md @@ -15,6 +15,14 @@ the subtitle-free 330×100 master, centered at 320px, followed by `
` and the `FUNCTIONAL REGRESSION EVIDENCE` line before the H1. The Demo reuses that SVG at 160px inside `.ax-product-header`. +Header activation follows home-navigation revision **2026-09-04.1**: wrap the wordmark in a +native `type="button"` with `data-alvenx-home` and the accessible name `AlvenX — Back to top`. +Use the canonical CSS reset/focus rules. Pointer, Enter and Space return the current document +to its true top; activation at the top is a no-op. Preserve the complete URL/history, current +view, results and running work. Reduced motion scrolls immediately; other activation is smooth. +The implementation lives in `src/demo/public/index.html` and `app.js`; the real-browser +regression lives in `tests/playwright/demo.spec.ts`. + The shared CSS controls the static four-layer background, typography, glass surfaces and header geometry. Product CSS may arrange the case/run workflow and add visible focus/reduced-motion behavior; it must not override approved header values or redraw the logo. diff --git a/harness/context/03-brand-verifiable-demo.md b/harness/context/03-brand-verifiable-demo.md index 3d3b20f..4e9481d 100644 --- a/harness/context/03-brand-verifiable-demo.md +++ b/harness/context/03-brand-verifiable-demo.md @@ -183,3 +183,31 @@ Ten current computed header properties match the preserved accepted Studio refer CSS is unchanged. Exact PR/main integration receipts are retained in `.workspace/audits/reprolock-english-demo-20260904/` in the parent AlvenX workspace and the PR, so recording the final merge does not change the tested source tree. + +## AlvenX header activation follow-up — 2026-09-04 + +English PR #4 merged as `5b16d22`; both its PR and main Node 22/24 CI jobs passed and the +fixed D checkout was clean before the owner added uniform logo activation through the brand +coordinating task. Branch `codex/alvenx-header-home` implements that scoped request with one writer. +Baseline `pnpm brand:verify` and `pnpm test:browser` passed (4/4) before editing. + +The native `AlvenX — Back to top` button wraps the unchanged wordmark. Its click handler returns +immediately at scrollY zero, otherwise scrolls the current document to top zero while preserving +scrollX; reduced motion uses `instant`, otherwise `smooth`. No navigation or execution state is +changed. The exact approved canonical CSS now includes the button reset and visible focus rules; +its SHA-256 is `b4bc3051213c2d9a1a37af80233d0b4978941d73c5945f6a792b84271e1d5c0c`. +Provenance records independent home-navigation revision `2026-09-04.1`. + +Actual `pnpm check` passed 80/80 unit/process and 4/4 browser tests. Existing browser coverage now +checks pointer, Enter and Space under normal and reduced motion, true document top, activation +at the top, and preservation of the selected saved result, export, expanded source, URL/hash, +history and document lifetime. The three widths retain the canonical geometry and 160px wordmark; +the button has visible keyboard focus. All historical and recorded evidence verifiers passed. +`pnpm package:smoke` passed (108 files / 370,413 bytes before this receipt update). +Shared brand validation passed 22 assets, five README headers and five header-navigation contracts; +workspace validation passed five independent repositories. Independent read-only review passed. + +The independent source export and exact PR/main CI integration receipts are recorded after the +source commit in `.workspace/audits/reprolock-header-home-20260904/` in the parent workspace and +the PR. This follow-up preserves all raw experiments and screenshots and does not repeat or +reclassify the historical 20+20 experiment. Product stage remains `SPIKE_CONDITIONAL`. diff --git a/plans/03-brand-verifiable-demo.md b/plans/03-brand-verifiable-demo.md index dfb9a80..634bea5 100644 --- a/plans/03-brand-verifiable-demo.md +++ b/plans/03-brand-verifiable-demo.md @@ -105,3 +105,18 @@ merge receipts are retained in the PR and local audit without changing the teste - [x] English copy, documentation and current screenshot. - [x] Browser/resource/layout, independent-export and configured engineering checks. - [x] Independent review; exact-head PR/merge receipts close integration in the PR/local audit. + +## AlvenX header activation — 2026-09-04 + +After English PR #4 merged as `5b16d22`, the owner requested the same header-logo activation +across all AlvenX interfaces through the coordinating brand task. ReproLock remains under one +writer in the fixed D checkout, branch `codex/alvenx-header-home`. Baseline `pnpm brand:verify` +and `pnpm test:browser` passed (4/4) before editing. + +Use the canonical native `data-alvenx-home` button and shared CSS revision 2026-09-04.1. +Activation returns the document to its true top, does nothing at the top, respects reduced +motion and preserves the URL/history, current view, results and running work. Keep the existing +160px wordmark and header geometry. Update the existing browser coverage for pointer/keyboard +activation and retained state, verify the canonical assets and independent export, then review, +submit, follow both Node CI jobs, merge and synchronize D main. Preserve the English delivery +and all historical evidence; this changes interface behavior only. diff --git a/scripts/verify-brand.mjs b/scripts/verify-brand.mjs index 473cc0e..1495408 100644 --- a/scripts/verify-brand.mjs +++ b/scripts/verify-brand.mjs @@ -10,6 +10,7 @@ export async function verifyBrand(root) { assert.equal(provenance.schemaVersion, 1); assert.equal(provenance.brandRevision, "2026-08-24.1"); assert.equal(provenance.interfaceRevision, "2026-08-25.2"); + assert.equal(provenance.homeNavigationRevision, "2026-09-04.1"); const names = [ "alvenx-wordmark.svg", "alvenx-monogram.svg", @@ -43,6 +44,7 @@ export async function verifyBrand(root) { readmes: readmes.length, brandRevision: provenance.brandRevision, interfaceRevision: provenance.interfaceRevision, + homeNavigationRevision: provenance.homeNavigationRevision, }; } diff --git a/src/demo/public/app.js b/src/demo/public/app.js index 5fbcb25..c94bcdf 100644 --- a/src/demo/public/app.js +++ b/src/demo/public/app.js @@ -25,6 +25,15 @@ const results = { "browser-runtime-error": "Browser runtime error", }; +document.querySelector("[data-alvenx-home]").addEventListener("click", () => { + if (window.scrollY === 0) return; + window.scrollTo({ + top: 0, + left: window.scrollX, + behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "instant" : "smooth", + }); +}); + async function control(action) { const response = await fetch(`/api/${action}`, { method: "POST", diff --git a/src/demo/public/index.html b/src/demo/public/index.html index 4766217..85ba4e4 100644 --- a/src/demo/public/index.html +++ b/src/demo/public/index.html @@ -13,7 +13,7 @@
- AlvenX +
diff --git a/tests/playwright/demo.spec.ts b/tests/playwright/demo.spec.ts index b12efc9..57bc114 100644 --- a/tests/playwright/demo.spec.ts +++ b/tests/playwright/demo.spec.ts @@ -33,6 +33,9 @@ test("Demo loads standalone brand resources and preserves canonical responsive h page.on("pageerror", (error) => errors.push(error.message)); await page.goto(demo.address); await expect(page.locator("html")).toHaveAttribute("lang", "en"); + const home = page.getByRole("button", { name: "AlvenX — Back to top", exact: true }); + await expect(home).toHaveAttribute("type", "button"); + await expect(home).toHaveAttribute("data-alvenx-home", ""); await expect(page.locator("#history-verification")).toContainText("frozen inputs verified"); for (const width of [390, 900, 1440]) { await page.setViewportSize({ width, height: 1000 }); @@ -70,6 +73,8 @@ test("Demo loads standalone brand resources and preserves canonical responsive h expect( await page.locator("#start").evaluate((element) => getComputedStyle(element).outlineStyle), ).toBe("solid"); + await home.focus(); + expect(await home.evaluate((element) => getComputedStyle(element).outlineStyle)).toBe("solid"); await page.emulateMedia({ reducedMotion: "reduce" }); expect(await page.evaluate(() => getComputedStyle(document.documentElement).scrollBehavior)).toBe( "auto", @@ -85,7 +90,7 @@ test("Demo loads standalone brand resources and preserves canonical responsive h expect(errors).toEqual([]); }); -test("startup failure has zero current observations and can be reopened without reloading", async ({ +test("saved startup failure survives header home activation without navigation or reloading", async ({ page, }) => { await page.goto(demo.address); @@ -100,6 +105,39 @@ test("startup failure has zero current observations and can be reopened without await expect(page.locator("#timing")).toContainText("Not re-executed"); const exported = await page.request.get(`${demo.address}/api/export/${id}`); expect((await exported.json()).schemaVersion).toBe(1); + + await page.getByRole("link", { name: "ReproLock", exact: true }).click(); + await page.getByText("Inspect the frozen test", { exact: true }).click(); + const retainedState = () => + page.evaluate(() => ({ + url: location.href, + historyLength: history.length, + historyState: history.state, + documentStarted: performance.timeOrigin, + run: document.querySelector(".run-panel")?.textContent, + export: document.querySelector("#export")?.getAttribute("href"), + sourceOpen: document.querySelector(".source-detail")?.hasAttribute("open"), + })); + const before = await retainedState(); + expect(before.url).toContain("#main"); + expect(before.sourceOpen).toBe(true); + const home = page.getByRole("button", { name: "AlvenX — Back to top", exact: true }); + for (const reducedMotion of ["no-preference", "reduce"] as const) { + await page.emulateMedia({ reducedMotion }); + for (const activation of ["click", "Enter", "Space"]) { + await page.evaluate(() => + window.scrollTo({ top: document.documentElement.scrollHeight, behavior: "instant" }), + ); + await expect.poll(() => page.evaluate(() => window.scrollY)).toBeGreaterThan(0); + if (activation === "click") await home.click(); + else await home.press(activation); + await expect.poll(() => page.evaluate(() => window.scrollY)).toBe(0); + expect(await retainedState()).toEqual(before); + } + await home.click(); + expect(await page.evaluate(() => window.scrollY)).toBe(0); + expect(await retainedState()).toEqual(before); + } }); test("concurrent controls admit exactly one configured run and reject foreign control requests", async ({