rastrillo / fiesta Public

The gallery's labels and the axe README in Fiesta's words

Every label the gallery chrome shows is now the text Paul approved,
applied byte for byte from the copy review's result: the 43 values in
internal/gallery/copy.go that were TODO-COPY placeholders, so
TestTheGalleryCarriesNoPlaceholderCopy passes and make root is green
again.

internal/axe/README.md's two rewritten sections, This is test data and
Upgrading, say what is true here: Scan in internal/axe runs the engine
over every example state's document in internal/gallery and over
check/'s fixtures; only this package embeds it; TestTheShippedTreeCarriesNoAxe
and TestVendoredAxeIsNotAShippedAsset hold the embed and the release;
and the scan runs as make browser.internal.gallery~1of2 and ~2of2. The
heading, the pin block and the first paragraph are as they were, and
TestVendoredAxeIsThePinnedVersion still reads the pin.

The .fiesta stamp names the command that wrote it, fiesta build or
fiesta gallery, in the sentence it already had: stampBody takes the
command's name, claim takes it too, and the refusal names it.
Human

Prompt

Task 13, Phase B: apply the 48 approved strings byte for byte, with no fixes; make the .fiesta stamp cover fiesta gallery using the words already there.

From this commit's own message. The prompt ledger has no entries for it — which is what a squashed, rebased or amended commit looks like, and what every commit looks like in a repo without a ledger.

Summary

Replaces the gallery's placeholder labels with the approved copy, rewrites the two axe README sections from the approved text, and has the ownership stamp name the command that wrote it.
Agent notes
go test ./... green, both gallery shards green; make ci run after the commit. The stamp sentence is unchanged except for the command's name in place of 'fiesta build'.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 788a59d16a0fd645df8e1a112279ea9e43b1e08f parent abfd6e9
5 files changed, +68 −77
  • cmd/fiesta/claim.go +15 −12
  • cmd/fiesta/claim_test.go +1 −1
  • cmd/fiesta/main.go +6 −5
  • internal/axe/README.md +3 −16
  • internal/gallery/copy.go +43 −43
diff --git a/cmd/fiesta/claim.go b/cmd/fiesta/claim.go
index 49ecd24..4f9031f 100644
--- a/cmd/fiesta/claim.go
+++ b/cmd/fiesta/claim.go
@@ -13,18 +13,21 @@ import (
// write, which was safe and left a renamed file published for as long
// as the build directory lived. The stamp is how it gets both.
-// stampName is the file fiesta build leaves in a directory to say the
-// directory is its own. Dotted so it stays out of the way of whatever
-// serves the tree.
+// stampName is the file fiesta build and fiesta gallery leave in a
+// directory to say the directory is its own. Dotted so it stays out of
+// the way of whatever serves the tree. One name for both commands: a
+// directory one of them wrote is a directory the other may empty.
const stampName = ".fiesta"
-const stampBody = `This directory is written by fiesta build, which EMPTIES it on every
-run. Do not keep anything here. Delete this file and fiesta build will
-refuse the directory instead.
-`
+// stampBody is what the stamp says, naming the command that wrote it.
+func stampBody(command string) string {
+ return "This directory is written by " + command + ", which EMPTIES it on every\n" +
+ "run. Do not keep anything here. Delete this file and " + command + " will\n" +
+ "refuse the directory instead.\n"
+}
-// claim makes root a directory fiesta build owns and empties it, or
-// fails without touching anything.
+// claim makes root a directory command (fiesta build or fiesta gallery)
+// owns and empties it, or fails without touching anything.
//
// Ownership is the whole of the safety story, and it is deliberately
// conservative: an absent directory is created, an empty one is
@@ -45,7 +48,7 @@ refuse the directory instead.
// leaves a directory the command still owns and will clean out on the
// next run. It is not atomic: a failed run leaves a partial tree
// behind, and the only thing saying so is the non-zero exit status.
-func claim(root string) error {
+func claim(root, command string) error {
entries, err := os.ReadDir(root)
switch {
case os.IsNotExist(err):
@@ -57,7 +60,7 @@ func claim(root string) error {
case len(entries) > 0:
if _, err := os.Stat(filepath.Join(root, stampName)); err != nil {
return fmt.Errorf("refusing to empty %s: it is not empty and holds no %s stamp, "+
- "so fiesta build has not written it before. Empty it yourself, or point -out somewhere else", root, stampName)
+ "so %s has not written it before. Empty it yourself, or point -out somewhere else", root, stampName, command)
}
for _, e := range entries {
if err := os.RemoveAll(filepath.Join(root, e.Name())); err != nil {
@@ -65,7 +68,7 @@ func claim(root string) error {
}
}
}
- if err := os.WriteFile(filepath.Join(root, stampName), []byte(stampBody), 0o644); err != nil {
+ if err := os.WriteFile(filepath.Join(root, stampName), []byte(stampBody(command)), 0o644); err != nil {
return fmt.Errorf("writing %s: %w", filepath.Join(root, stampName), err)
}
return nil
diff --git a/cmd/fiesta/claim_test.go b/cmd/fiesta/claim_test.go
index d6f05e2..e4df0e4 100644
--- a/cmd/fiesta/claim_test.go
+++ b/cmd/fiesta/claim_test.go
@@ -57,7 +57,7 @@ func TestBuildRefusesADirectoryItDoesNotOwn(t *testing.T) {
if _, err := os.Stat(stray); !os.IsNotExist(err) {
t.Errorf("the stray file survived a build into a directory the command owns: %v", err)
}
- if b, err := os.ReadFile(filepath.Join(root, stampName)); err != nil || string(b) != stampBody {
+ if b, err := os.ReadFile(filepath.Join(root, stampName)); err != nil || string(b) != stampBody("fiesta build") {
t.Errorf("the stamp was not rewritten: %q, %v", b, err)
}
diff --git a/cmd/fiesta/main.go b/cmd/fiesta/main.go
index e86ebc7..f2d107a 100644
--- a/cmd/fiesta/main.go
+++ b/cmd/fiesta/main.go
@@ -118,7 +118,7 @@ func write(out string) error {
if err != nil {
return err
}
- return writeTree(filepath.Join(out, fiesta.Version), dist)
+ return writeTree(filepath.Join(out, fiesta.Version), "fiesta build", dist)
}
// writeGallery renders the gallery for mount and puts it in out, a
@@ -128,16 +128,17 @@ func writeGallery(out, mount string) error {
if err != nil {
return err
}
- return writeTree(out, files)
+ return writeTree(out, "fiesta gallery", files)
}
-// writeTree claims root and writes files under it, in name order.
-func writeTree(root string, files map[string][]byte) error {
+// writeTree claims root for command and writes files under it, in
+// name order.
+func writeTree(root, command string, files map[string][]byte) error {
root, err := filepath.Abs(root)
if err != nil {
return fmt.Errorf("resolving -out: %w", err)
}
- if err := claim(root); err != nil {
+ if err := claim(root, command); err != nil {
return err
}
names := make([]string, 0, len(files))
diff --git a/internal/axe/README.md b/internal/axe/README.md
index 059d851..d631e02 100644
--- a/internal/axe/README.md
+++ b/internal/axe/README.md
@@ -13,23 +13,10 @@ and not from the network.
## This is test data
-It is read by `internal/designsystem/a11y_test.go` (build tag `browser`), which
-injects it into a headless Chromium and scans the design-system gallery —
-served straight out of `designsystem.Render()`, in memory, since the gallery is
-generated at the publishing site's build rather than kept in this repository.
-The engine is not embedded, not served, not part of `ui.ShimJS()`, and reaches
-none of the 369 files the gallery renders. Two untagged tests assert all of
-that, so they run on every `go test ./...` and not only when a browser is
-around: `TestVendoredAxeIsNotAShippedAsset` in `ui/axe_test.go` holds the
-library's assets and the embedded template tree, and
-`TestVendoredAxeStaysOutOfTheTree` in `internal/designsystem` holds the render.
+It is read by `internal/axe`, whose `Scan` (build tag `browser`) injects it into a headless Chromium and runs it over the page a drive is on: every example state as its own document in `internal/gallery`, and the fixtures the drives in `check/` serve. Only this package embeds the engine. The root package embeds `css/`, `js/`, `icons/`, `examples/`, `i18n/` and `LICENSE`, so nothing a Go program imports from Fiesta carries it, and two untagged tests hold that on every `go test ./...`, not only when a browser is around: `TestTheShippedTreeCarriesNoAxe` beside this file walks the embedded tree for the engine's banner and checks that the public packages never import this one, and `TestVendoredAxeIsNotAShippedAsset` in `internal/build` walks the release.
## Upgrading
-Fetch the new version from both CDNs above, check the two copies are identical,
-replace the file, and update the version and sha256 in this README —
-`TestVendoredAxeIsThePinnedVersion` reads both out of this file and fails if
-either stops describing what is on disk. Then run the scan: a new axe-core
-finds things the old one did not, and those findings are the point.
+Fetch the new version from both CDNs above, check the two copies are identical, replace the file, and update the version and sha256 in this README. `TestVendoredAxeIsThePinnedVersion` reads both out of this file and fails if either stops describing what is on disk. Then run the scan: a new axe-core finds things the old one did not, and those findings are the point.
- go test -tags browser -run A11y ./internal/designsystem/
+ make browser.internal.gallery~1of2 browser.internal.gallery~2of2
diff --git a/internal/gallery/copy.go b/internal/gallery/copy.go
index b6e216c..fefd570 100644
--- a/internal/gallery/copy.go
+++ b/internal/gallery/copy.go
@@ -12,61 +12,61 @@ import "strings"
var text = map[string]string{
// The <title> of every page: the page first, because a tab strip
// truncates from the end, then the site, then the theme.
- "gallery.title": "TODO-COPY:gallery.title",
+ "gallery.title": "{page} · Fiesta · {theme}",
// The brand link at the start of the header, back to the index.
- "gallery.brand": "TODO-COPY:gallery.brand",
+ "gallery.brand": "Fiesta",
// The skip link, first in every page.
- "gallery.skip": "TODO-COPY:gallery.skip",
+ "gallery.skip": "Skip to content",
// The theme switcher's accessible name.
- "gallery.theme.label": "TODO-COPY:gallery.theme.label",
+ "gallery.theme.label": "Theme",
// The link to the page's right-to-left twin, and back.
- "gallery.direction.rtl": "TODO-COPY:gallery.direction.rtl",
- "gallery.direction.ltr": "TODO-COPY:gallery.direction.ltr",
+ "gallery.direction.rtl": "Right to left",
+ "gallery.direction.ltr": "Left to right",
// The page navigation: its accessible name and its three links.
- "gallery.nav.label": "TODO-COPY:gallery.nav.label",
- "gallery.nav.examples": "TODO-COPY:gallery.nav.examples",
- "gallery.nav.tokens": "TODO-COPY:gallery.nav.tokens",
- "gallery.nav.icons": "TODO-COPY:gallery.nav.icons",
+ "gallery.nav.label": "Pages",
+ "gallery.nav.examples": "Examples",
+ "gallery.nav.tokens": "Tokens",
+ "gallery.nav.icons": "Icons",
// The index: its heading, its lead, and a heading per family.
- "gallery.index.heading": "TODO-COPY:gallery.index.heading",
- "gallery.index.lead": "TODO-COPY:gallery.index.lead",
- "gallery.family.list-screen": "TODO-COPY:gallery.family.list-screen",
- "gallery.family.display": "TODO-COPY:gallery.family.display",
- "gallery.family.form": "TODO-COPY:gallery.family.form",
- "gallery.family.choices-and-actions": "TODO-COPY:gallery.family.choices-and-actions",
- "gallery.family.date-and-time": "TODO-COPY:gallery.family.date-and-time",
- "gallery.family.route": "TODO-COPY:gallery.family.route",
- "gallery.family.primitives": "TODO-COPY:gallery.family.primitives",
- "gallery.family.shells": "TODO-COPY:gallery.family.shells",
- "gallery.family.formats": "TODO-COPY:gallery.family.formats",
- "gallery.family.screens": "TODO-COPY:gallery.family.screens",
+ "gallery.index.heading": "Examples",
+ "gallery.index.lead": "Every state of every example in the {theme} theme, each as a page of its own. Open an example to see its states live, with the markup beside each one.",
+ "gallery.family.list-screen": "List screen",
+ "gallery.family.display": "Display",
+ "gallery.family.form": "Form",
+ "gallery.family.choices-and-actions": "Choices and actions",
+ "gallery.family.date-and-time": "Date and time",
+ "gallery.family.route": "Route",
+ "gallery.family.primitives": "Primitives",
+ "gallery.family.shells": "Shells",
+ "gallery.family.formats": "Formats",
+ "gallery.family.screens": "Screens",
// An example's page: the sentence under its heading, the HTML tab,
// the frame's accessible name, and the note naming the routes a
// sample stands for.
- "gallery.example.lead": "TODO-COPY:gallery.example.lead",
- "gallery.html": "TODO-COPY:gallery.html",
- "gallery.frame.title": "TODO-COPY:gallery.frame.title",
- "gallery.routes": "TODO-COPY:gallery.routes",
+ "gallery.example.lead": "Each state is live, but its links go nowhere. HTML shows the markup to copy.",
+ "gallery.html": "HTML",
+ "gallery.frame.title": "{example}: {state}",
+ "gallery.routes": "In an app this would reach {routes}. Here its links and forms go nowhere.",
// The tokens page: heading, lead, the note on the palette, and a
// heading per group of tokens.Group.Key.
- "gallery.tokens.heading": "TODO-COPY:gallery.tokens.heading",
- "gallery.tokens.lead": "TODO-COPY:gallery.tokens.lead",
- "gallery.tokens.note": "TODO-COPY:gallery.tokens.note",
- "gallery.tokens.group.surfaces-and-lines": "TODO-COPY:gallery.tokens.group.surfaces-and-lines",
- "gallery.tokens.group.text": "TODO-COPY:gallery.tokens.group.text",
- "gallery.tokens.group.accent": "TODO-COPY:gallery.tokens.group.accent",
- "gallery.tokens.group.status-tones": "TODO-COPY:gallery.tokens.group.status-tones",
- "gallery.tokens.group.depth": "TODO-COPY:gallery.tokens.group.depth",
- "gallery.tokens.group.controls": "TODO-COPY:gallery.tokens.group.controls",
- "gallery.tokens.group.type-choices": "TODO-COPY:gallery.tokens.group.type-choices",
- "gallery.tokens.group.other": "TODO-COPY:gallery.tokens.group.other",
- "gallery.tokens.group.radius": "TODO-COPY:gallery.tokens.group.radius",
- "gallery.tokens.group.type-family": "TODO-COPY:gallery.tokens.group.type-family",
- "gallery.tokens.group.type-scale": "TODO-COPY:gallery.tokens.group.type-scale",
- "gallery.tokens.group.spacing": "TODO-COPY:gallery.tokens.group.spacing",
+ "gallery.tokens.heading": "Tokens",
+ "gallery.tokens.lead": "The custom properties every component reads. Colour, type family and shape come from the theme, css/themes/{theme}.css. The type scale and the spacing steps are structure, the same in every theme, and come from css/tokens.css.",
+ "gallery.tokens.note": "Light values shown. Every colour is declared once as a light-dark() pair, and the chips follow the scheme menu above. WCAG 2.2 AA floors: 4.5:1 for text, 3:1 for control borders.",
+ "gallery.tokens.group.surfaces-and-lines": "Surfaces and lines",
+ "gallery.tokens.group.text": "Text",
+ "gallery.tokens.group.accent": "Accent",
+ "gallery.tokens.group.status-tones": "Status tones",
+ "gallery.tokens.group.depth": "Depth",
+ "gallery.tokens.group.controls": "Controls",
+ "gallery.tokens.group.type-choices": "Type choices",
+ "gallery.tokens.group.other": "Other",
+ "gallery.tokens.group.radius": "Radius",
+ "gallery.tokens.group.type-family": "Type family",
+ "gallery.tokens.group.type-scale": "Type scale",
+ "gallery.tokens.group.spacing": "Spacing",
// The icons page: heading and lead.
- "gallery.icons.heading": "TODO-COPY:gallery.icons.heading",
- "gallery.icons.lead": "TODO-COPY:gallery.icons.lead",
+ "gallery.icons.heading": "Icons",
+ "gallery.icons.lead": "{total} icons from Lucide, each an inline SVG sized from the text beside it by tokens.css's own .icon rule, which is the size shown here.",
}
// say returns the text filed under id, with each {name} replaced by