1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172# First full run, 2026-08-27
The numbers below are what the run produced, not projections.
## What the pipeline moved
seeds 117 URLs across 7 sector files
pages fetched 524 distinct pages on 67 domains
candidates found 11,334 in pool/candidates.jsonl
survived the caps 967 in pool/shortlist.jsonl
selected 250 into corpus/functional-images.jsonl
images archived 965 files, 30 MB, in pool/images/
reviewed 250 in 9 batches of 30, 30, 30, 30, 30, 30, 30, 30, 10
ready 78
dropped 172
exported 78 to projects/corpus-validation/
Every candidate in the pool already had an accessible name, because
`harvest.mjs` never writes a record for an image whose control has no name. That
is the collection rule, applied at the point of collection rather than as a
later filter, so the count of nameless images found is not recorded. It is
large: most images on most pages are not in a control at all.
## Why 172 were dropped
weak 143 the alt exists and is not good enough
good 21 the alt is good, but the item does not belong
wrong 8 the alt states something that is not true
The 21 `good` drops split two ways. Most are correct alt text on an image that
turned out not to be functional: news photographs, book covers, avatars,
illustrations. Seven are duplicates of a template already kept, which is a
different thing and is discussed in
[batch-08-notes.md](batch-08-notes.md).
The 143 `weak` drops are dominated by one finding, which recurred in every
batch: a linked logo whose alt is the bare brand name, on a link to the site's
own root. The criteria in the root README are explicit that the destination is
what matters, so `alt="Acme"` on a link home is weaker than `alt="Acme home"`.
Six sites shipped both versions of that alt, on the same page or elsewhere on
the same site: W3C, Library of Congress, SourceForge, Al Jazeera, UC Berkeley
and the National Park Service. A site correcting itself is more persuasive than
any two sites compared to each other, and those six pairs are the strongest
evidence in the corpus that the criterion is real rather than a matter of
taste.
The 8 `wrong` drops are the clearest defects found. Two are on weather.gov and
are the same copy-paste mistake twice, described in
[batch-09-notes.md](batch-09-notes.md).
## What reached human review
78 items. By sub-type:
28 action-or-toggle-icon
20 linked-standalone-logo
20 standalone-navigational-link
5 form-control-or-image-button
4 linked-complex-graphic-or-image-map
1 structural-break-or-reader-control
0 functional-non-unicode-emoji
By sector: 16 government, 13 docs, 10 commerce, 10 education, 10 publishing,
10 webapp, 9 news.
36 of the 78 have no usable alt attribute on the image itself; the text lives on
the link or button. 7 of those 36 carry a deliberate `alt=""`, which is the
correct answer, and the rest carry no alt attribute at all and are named by an
`aria-label`, a `title`, or an SVG `<title>`.
## Findings for the next harvest
These are ordered by how much they would improve the next run.
1. **The logo-versus-link test is wrong.** `harvest.mjs` decides between
`linked-standalone-logo` and `standalone-navigational-link` by comparing the
href against the site root as a string. That mislabelled items in all nine
batches: wiki main pages, locale home pages such as `/en.html` and
`/content/canadasite/en.html`, off-site roots, and Wayfair's `handover.php`
redirects. The proposal should treat any href that resolves to another site's
origin root, or to a known home-page path, as a logo.
2. **Duplicate templates survive the dedup.** `select.mjs` dedupes on the
`image_sha256` and `element_role` pair, which misses anything a build tool
varies per render: generated `id` attributes, per-instance colour classes,
cache-busting query strings. Seven duplicates reached review. Dedupe on a
normalised `element_html` as well: strip attribute values that look
generated, then hash the remainder.
3. **`aria-hidden` is honoured on the image but not on the ancestor.**
`fi-7285` is a BBC account link carrying both `hidden` and `aria-hidden` on
the interactive ancestor, so it is hidden from everyone, and it was still
collected. Walk the ancestor chain for `aria-hidden` before writing a record.
4. **The accessible name misses text siblings of the image.** For `fi-5357` and
`fi-5591` the name was computed as the control's text node alone, dropping
the image's own alt from the concatenation. A browser announces both. This
changes what is under review, so it matters more than its two occurrences
suggest.
5. **MediaWiki links every image to its own file description page.** That makes
`harvest.mjs` see an interactive ancestor around images nobody made
interactive. Worth a special case, or worth accepting that wiki domains
produce a high proportion of platform artefacts.
6. **`functional-non-unicode-emoji` is empty after 250 items**, and
`structural-break-or-reader-control` has one. These are real categories in
the taxonomy, but they do not appear on the front pages of the kind of sites
this seed list crawls. Either seed specifically for them, or record that the
taxonomy is aspirational in those two places.
7. **`commerce` holds 17 of a wanted 20.** The commerce seeds yielded fewer
named controls than the other sectors, which is itself a finding about
retail sites.
Two limitations already stated in the plan still hold, and both bound what this
corpus can contain: CSS background images and icon fonts are skipped, because
their bytes cannot be archived from the markup alone, and JavaScript-rendered
pages are not executed, which is why web application icons stay thin.
## Found after the run, while checking the export by hand
Three things surfaced only once a person looked at what the review had passed.
All three are fixed; they are recorded because each one was invisible from the
counts above.
8. **The image maps could not be judged as archived.** For an `<area>`,
`fetch-images.mjs` archives the parent `<img usemap>`, so all four items in
`linked-complex-graphic-or-image-map` showed a whole national map against alt
text naming one region. `fi-5153` was a full US forecast chart against
`alt="Northeast Michigan"`. The validation tool now draws the region as an
outline over the map and states its position in words. Nothing was wrong with
the data; the reviewer could not see what the alt text referred to.
9. **`<area>` coordinates are not in the archived file's pixel space.** They are
CSS pixels of the map as its own page rendered it.
`weather.gov/forecastmaps` puts `width="370"` on a map whose file is 512
pixels wide, so the first overlay placed Northeast Michigan over North
Dakota. `harvest.mjs` now records the rendered size as `image_coord_space`,
and the field is backfilled for the four existing items from a later fetch of
the same four pages: `fi-5153` is `370x296`, `fi-5297` is `823x630`, and
`fi-4921` and `fi-5375` state no width or height, so their coordinates are in
the file's own space. The pool and shortlist rows were backfilled as `null`,
which is honest for a non-`area` row and an admission for the rest: their
pages were not refetched.
10. **`fi-5297` and `fi-5375` are duplicates of each other.** Identical alt text
and identical coordinates, on two different weather.gov pages. Both were
kept in batch 01, before the duplicate rule existed in batch 07. Finding 2
above would catch them today.
One reporting defect in this document's own source, worth stating plainly.
`validate.mjs` counts every item against the goal regardless of `status`, so
`./run.sh --status` printed "250 item(s), goal 250" when 78 were `ready`. The
coverage bars share the flaw: a dropped item still counts toward its sub-type
quota. Read the `ready` line, not the total.
## The archive after cleanup
`tools/cleanup.mjs` was run with `--apply --drop-unselected`, which deleted 172
reviewed-and-dropped images and 715 that were downloaded but never selected,
leaving the 78 the benchmark uses, 3.3 MB. Every deletion is listed in
`pool/images-removed.txt` with its reason. Growing the corpus now needs a fresh
harvest rather than another `--select`, which is the cost the flag names.