Living checklist of open items. Everything not listed here is done and live at https://ethical-tech-colab.github.io/website/.
Working an item means regenerating the tracked snapshot, not only editing
src/ — see CONTRIBUTING §4.
This applies to any change to the site, not just adding an asset: a content
edit that skips npm run sync:static leaves static-site/ describing a
version of the site that no longer exists.
Last updated: 2026-08-05.
Every team member now has a headshot in public/team/ (new ones are added by
dropping a file into the local "Pictures website" folder and converting it to
public/team/<slug>.jpg; filenames must match the photo path in site.ts).
Done: founder, advisors (incl. Teresa Cantero and Sylvia Maier), all Summer 2026 / Fall 2025 researchers, staff, collaborators, and all six Spring 2025 headshots (Smita Samanta, Elizabeth Matthews, Renata Gladkikh, Jennifer Hofmann, Emily Harrington, Natasha Nagarajan).
Drop into public/logos/ (auto-discovered by filename; falls back to a
monogram). See public/logos/README.md.
These render in the Partners & collaborators band at the bottom of /team.
They used to live only on /about, which is hidden (§7), so until 2026-07-23
any logo added here appeared nowhere.
That band is one merged list of 19 organisations — founding partners first,
then everyone else. about still stores founding partners, clients, and
partners as three separate arrays because the hidden /about page renders them
that way; /team concatenates them. The "Clients" grouping was dropped from the
public view on 2026-07-23: the client/partner split was not a distinction worth
making to a visitor. If /about is ever restored, decide whether it should
match /team or keep the three-way split.
Still showing a monogram (no file yet):
-
mesur-io.*— no longer needed. The org rebranded to Tradeverifyd in 2025;tradeverifyd.svg(the dark wordmark, which reads on the white logo tile) is in place and the partner entry is updated. -
supplytrace.*— no longer needed. SupplyTrace was removed from the organisations grid on 2026-08. -
human-generated-by-blockapps.*— no longer needed. Human Generated by BlockApps was removed from the organisations grid on 2026-08-25. -
osce-odihr-anti-trafficking.*— checked 2026-08-25: there is nothing to recover here. No OSCE/ODIHR logo has ever been committed to this repository, under that name or any other:git log --diff-filter=Doverpublic/logosreturns zero deletions, so no logo file has ever been removed. The entry has carriedlogo: ""since Carolina added it ina30def40(2026-07-21), and itsabouttext andurlare byte-identical to that commit — nothing was lost. A search of every repository in the organisation finds only text references. So this needs a file sourced from OSCE/ODIHR, not restored. Worth doing deliberately rather than by grabbing the emblem off osce.org: it is a protected intergovernmental emblem with its own usage rules, which is a different question from the company wordmarks in this folder. - Better source files for the two screenshot logos — Art & Antiquities Blockchain Consortium and Blockchain for Social Impact were supplied as screen grabs, so they carry their page background (cream and white) rather than transparency, and cannot scale cleanly. Ask each for a PNG/SVG on transparent.
- Sayari renders small — the supplied wordmark is ~5.7:1, so inside the 56px square tile it lands about 56×10px. A stacked or icon-only mark would read better.
Done: Microsoft (microsoft.svg), NYU SPS + CGA (nyu-sps-cga-logo.jpg),
and added 2026-07-23 from the local "Partners Logos" folder — Generative AI for
Good, D_ID, Rivr, 100x, Apne Aap Women Worldwide, Gaia, Grid Bank — plus
Sayari, Art & Antiquities Blockchain Consortium, and Blockchain for Social
Impact, which were new organisations and needed partners entries too. Each is
wired to an explicit logo: path in site.ts so the browser skips the
extension-probe fallback. Gaia's supplied file was near-white on transparency
and would have been invisible on the white logo tile, so it was recoloured to
the light-theme ink (#1a1020); swap in a dark-on-transparent original if the
brand team provides one.
Added later the same day: NYU SPS now has its own SPS lockup
(/logos/nyu-sps.jpg, trimmed from a wide export and re-centred on NYU purple)
— it had been pointing at the CGA logo, so the school and the centre showed the
same mark. Coinbase and x402 Foundation were split out of a single
"Coinbase & x402 Foundation" entry so each could carry its own logo. UN
Commission on the Status of Women (CSW) was removed from partners entirely.
- Website URLs for clients still blank: Generative AI for Good, Rivr. (D_ID and Tradeverifyd are already linked. SupplyTrace and Human Generated by BlockApps were both removed from the grid, so neither needs one.)
- Short "what we do together" blurbs + URLs for partners: 100x, Apne Aap Women Worldwide (url set), Gaia, Grid Bank.
- Confirm the collaboration for the three partners added 2026-07-23 —
Sayari, Art & Antiquities Blockchain Consortium, and Blockchain
for Social Impact. Their
abouttext currently describes what each organisation does, sourced from its own site, because the CoLab's actual relationship with each was not confirmed. Rewrite each as a "what we do together" line (as OSCE/ODIHR and Coinbase have) once known — and check they belong under Partners rather than Clients.
Posters render in a 2:3 portrait frame with bg-cover bg-top, in all three
places they appear (RepoShowcase, PortfolioExplorer, DemoRunner). A
1440×900 screenshot dropped in that frame shows only its centre 42%, so any
screenshot with a flush-left headline gets sliced mid-word.
Eleven posters were re-cropped left-anchored to 600×900 on 2026-07-23 — the four new project ones (Provenance Search, Digital Passport for Artworks, AI's Carbon Footprint, AI Research Question Assistant) and all seven practice-guide ones. The wide originals are in git history, in the commits that first added them.
- The other 16 posters are still wide and centre-cropped. Most read acceptably (War-Games and Avatar Storytelling centre well; MVDC shows its map), so this is a look-and-see pass, not a defect list. Check each in the 2:3 frame before deciding.
- Consider a
posterFocusfield instead. Re-cropping is lossy and has to be redone if the frame ratio ever changes. A"left" | "center"field onProduct/RunnableDemo, mapped tobackground-positionin the three components, would keep the wide originals and fix the framing in CSS. Not done on 2026-07-23 only because it touches five files and the site was being presented that day. - Synthetic Data & Seeding Models has a centred title slide, so no 2:3 crop shows the whole title. It reads "Synthetic Da…" left-anchored. A re-shot portrait screenshot is the only real fix.
-
3D Online Gallery — needs a hosted URL (Cultural-heritage project).
-
Arts Provenance Agent — a static mock demo is live. PR arts-provenance-agent#1 is still open if you want the full server version (real SSE stream) on Render instead.
-
Provenance Search — repo is public now, but it's a server app with no live demo yet (needs hosting).
-
Portfolio archive — missing live demos. These previous-cohort projects have no live-demo link yet, so their card shows no
+to expand. Add ademo(single URL),demos(list of{label, href}), and/orrepoto the matching entry inarchivedProjects(src/content/site.ts) and the+-to-open live demo appears automatically (as it now does for Forced Labor Structural Risk Index and Avatar Storytelling).- Online Grooming Prevention (Spring 2025)
- ESG Labels & Certificates Transparency (Spring 2025)
- AI's Carbon Footprint (Spring 2025)
- Academic Research Tool (Fall 2025)
-
Avatar Impact Stories — fold Live demos 1, 2 and 3 into the kiosk. The code is deployed (2026-08-05):
Avatar-Impact-Storiesis public and the Many Voices kiosk runs at https://ethical-tech-colab.github.io/Avatar-Impact-Stories/, wired to theavatar-storytellingproduct and thearchivedProjectsentry insrc/content/site.ts.What is left is that the kiosk plays only the stories in the repo's `stories.json`. Live demo 1, 2 and 3 are separate D-ID pieces that are not in it. Add them as `stories.json` entries (each needs a `poster`/`posterWebp` GIF and an `mp4` in `final_gifs/`, exported from D-ID) so all the testimonies play in one place. Same for demo 4. The site no longer links the D-ID shares — as of 2026-08-08 `avatarStorytellingDemo` is a single URL pointing at the kiosk, so the only way these three reach an audience is inside it. The share URLs, and the impact-dashboard walkthrough that was dropped with them, are in git history at commit `160dc254` if they are needed again. -
Avatar Impact Stories — clean up the story titles; take the student names out. Every title in the repo's
stories.jsonis shown as the caption under the playing avatar, and several still carry the name of the researcher who produced the piece rather than the story: Adam (Child Labour) - Alexa, Amala (Child Labour) - Alexa, Unethical Labour - Josh (Alexa), Domestic Violence 1/2/3 - Smita Samanta, Human Trafficking - Smita Samanta, Dorothy's Story - Nate, Forced Labor - Celine R. Strip the credit from each caption — credit belongs onabout.html, not on a survivor's testimony.While in there, the same list has titles that are working filenames rather than captions and need real ones: *arabic*, *vid*, *zoti*, *zoti (1)*, *zoti (2)*, *Survivor - Forced Labor #4*. And *The True Cost of Your Chocolate ΓÇô A Cocoa Farmer Speaks* has a mojibake en-dash — the file was written as cp1252 and read as UTF-8, so fix the encoding rather than just the one character. Note that `title` is derived from the media filename by the manifest generator (`tools/`), so either rename the files in `final_gifs/` or give each story an explicit `title` that the generator preserves — otherwise the next regeneration undoes the edit. -
Previous-cohort projects — gather missing links & content. Track down the remaining repos, live demos, write-ups, and descriptions for earlier cohorts' projects (Spring 2025 and Fall 2025) so the archive cards and Live Demos page are complete rather than name-only.
The four umbrella placeholder cards (indices 01–04: AI-Informed Evacuation Decision-Making, Verifiable Provenance for the Ethical Return…, Making Ethical Supply-Chain Claims Verifiable, Rehearsing High-Stakes Diplomacy…) were removed on 2026-07-23. Each promised a synthesis report that did not exist, and every area they covered is served by published reports already on the site — Evacuation by 07–12 and 27, Cultural heritage by 13–15, Traceability by 16, Diplomacy by 17. Every catalogue entry now has a report behind it.
Two consequences worth knowing:
- The "In preparation" filter chip on
/publicationswas removed with them — with nothing unpublished left it returned an empty page. Restore it alongside the first entry that ships without aurl. - "Readable now" now filters on
readable()(has a url and is notaccess: "internal"), not onurlalone, so it excludes the seven CoLab-only guides rather than matching everything.
index is a React key and cover-art seed only, never displayed, so the 01–04
gap is invisible — do not renumber, it would reshuffle every cover.
-
B3IQ podcast — decide where talks and interviews live. Add "Why AI Builders Need to Own Their Compute with B3" to the site. There is nowhere obvious to put it today:
mediaholdspastEvents,decksandgallery, all framed around the Ethical Tech Summit ("Media · Ethical Tech Summit" / "The Summit, in the room."), and nothing on the site links out to a talk, podcast or interview. So this needs a placement decision before it can be implemented, not just an entry: - a newmediagroup (e.g. "Talks & appearances") with its own heading, which widens the Media page beyond the Summit and would want the eyebrow/heading reworded; or - a dedicated section, if more of these are expected; or - a link from the B3IQ organisation card on/team, if it is better read as context on that partnership than as CoLab media. Whichever is chosen: confirm who is speaking and in what capacity before it is presented as CoLab media, capture the publication date, and prefer linking the video over embedding it so no third-party player is loaded for every visitor. YouTube thumbnails are hotlinked from Google's CDN, so a local still is preferable if a thumbnail is wanted. -
Newsletter signup — the code side is done; this is now purely an account/config task. Recommendation (decided 2026, evaluated against "CRM + backend", "API → Google Form", and "browser → Google Form directly"): keep the site's existing Mailchimp direct-POST scaffold (
NewsletterSignup.tsx) rather than adding any server. On a static export the lowest-uptime-dependency option is always a direct browser→SaaS POST — this mirrors the/contactrecommendation in §10.6. Ranked against the alternatives: - A custom backend (own API in front of a CRM) adds a service you must host and patch for zero benefit over posting to the CRM directly — avoid. - "API → Google Form" has the same problem: the API hop adds an uptime dependency the direct-POST pattern doesn't need. - A Google Form accepts direct browser POSTs with no backend too, but it only writes rows to a Sheet — no sending, no unsubscribe, no compliance handling. Fine for lead capture, not a mailing list; would need a second, unbuilt step to get emails into whatever actually sends future editions. - Mailchimp (or HubSpot's public Forms Submit API, if the CoLab already runs HubSpot) both captures and sends and handles unsubscribe/compliance, with Mailchimp's uptime — not something this repo has to run. Next step (not a code task): whoever owns the CoLab's Mailchimp account creates an embedded signup form there, then pastes the generatedactionURL and hidden anti-bot field name intonewsletter.action/newsletter.hiddenFieldinsrc/content/site.ts. See the step-by-step indocs/CONTENT-GUIDE.md. The form is already wired to switch from "coming soon" to live the moment those two strings are non-empty. -
Instagram — handle appears to be
@NYUSPS_ETHICALTECH_LAB(from the summit deck); confirm and wire intosite.social. -
X / Twitter — handle to confirm + wire (currently placeholder).
-
LinkedIn URLs for collaborators Adeline Daab and Susan DeMinil — done. Susan de Menil's profile is linked. Adeline Daab has no public LinkedIn; her
websitefield points at NYU Gallatin's "My Gallatin Story" feature instead.
-
Fall 2025 alumni bios — done. All six (Alexa Shamie, Mohagani Townsend, Amanda Lindsey, Taylor Badt, Vedant Jain, Grace Driscoll) now have real sourced bios, plus LinkedIn links and photos.
-
Missing bios / resume blurbs — done. All five named here (Hannah Zhao, Kirsten Co, Alex Du, Adeline Daab, Susan deMenil) now have a
bio. No page on the site shows "Bio coming soon" any more, and every researcher, advisor and collaborator has both a bio and a contact link. -
Cohort project placeholders (Spring 2025: AI's Carbon Footprint, Generative AI for Good; Fall 2025: Academic Research Tool — LLM prompting; Summer 2026: Synthetic Data Guidelines for Beginners) — add descriptions or links if you want them to be more than name-only bullets.
-
Alex Du & Hannah Zhao were Spring 2025 fellows but are listed in their current roles (Staff / Collaborator), not under Spring 2025 Alumni. Decide whether to also list them there.
-
Summer 2026 cohort card says "Four projects" over five bullets (
cohortsinsrc/content/site.ts). The heading was corrected to four on 2026-07-23 to match the four research areas on/portfolio, and keeping all five bullets was a deliberate call — AI Models Research is cohort work but not one of the four portfolio questions. Either drop that bullet, or reword the heading so the count is not read as a count of the list. Still true on 2026-08-08. -
README overstates the Summer 2026 cohort.
README.mdsays "Four active projects, eight applied researchers"; the roster holds seven, and the site's own cohort card correctly says "7 researchers". Unlike the item above, this one is simply wrong rather than a deliberate call. -
Notify past cohorts / alumni — message old cohort members (Spring 2025, Fall 2025, and any earlier) to let them know their profile is now live on the website, so they can review it and flag any corrections.
-
Dead reference link — UN R2P (
after-the-corridor.ts). The citation "UN Office on Genocide Prevention and the Responsibility to Protect…" points at.../about-responsibility-to-protect.shtml, which 404s since un.org migrated off.shtml. Three sibling dead links were fixed on 2026-07-23 (Copernicus EMS →rapidmapping.emergency.copernicus.eu, Meta → the 2024 sustainability report, UCI → the guide root), but un.org blocks automated requests with a redirect loop, so the replacement could not be verified from the CLI. Open it in a browser, grab the current URL, and paste it in. -
About page is hidden — the whole
/aboutpage is currently disabled (removed from the nav; the route serves a 404). Nothing is deleted: the full layout is preserved as comments insrc/app/about/page.tsx, and all its content still lives in theaboutobject insrc/content/site.ts. Decide what to do with it, then restore by: (1) deleting thenotFound()stub and uncommenting the component inabout/page.tsx, and (2) re-adding{ label: "About", href: "/about" }tonavinsite.ts.
- Tavily search — token/credit usage. Confirm whether the searches that use Tavily are consuming tokens/credits, and how much, so usage doesn't run up unexpectedly.
- ACLED API keys — evacuation projects. Verify the ACLED API keys are still preserved (and valid) in the evacuation projects, so the data feeds don't silently break.
All twenty ETC Pages sites now serve the purple ETC mark as etc-icon.svg +
etc-icon.png, verified live. These are the things that pass could not settle.
- FLSRI: subresource-integrity hardening is committed but not deployed
(
forced-labor-structural-risk-index).main'spublic/adds SRIintegrity/crossoriginattributes to the Leaflet and topojson CDN tags, and pins topojson to 3.1.0; thegh-pagesbranch has none of it. The favicon went ontogh-pageson its own rather than shipping that change as a side effect, so five files (index.html,bundle.html,pages/explore.html,pages/profiles.html,pages/simulate.html) still differ between the two branches. Deployingpublic/→gh-pagesis a call for whoever wrote the hardening. - grant-valuation-tool cannot be rebuilt from source. The
gh-pagesbranch holds a Next.js static build, but the repo has nooutput: "export", no deploy script, and no workflow — the branch was pushed by hand, so nothing regenerates it. The favicon was applied to the branch directly for that reason;src/app/icon.svgonmainonly helps once a real build path exists. Worth adding an export config + deploy workflow before the next content change, or the branch drifts further from source. - arts-provenance-agent: watchlist and methodology — ✅ shipped. The
stolen-art watchlist landed via PR #6 and the limits copy via PR #7. A
Methodology tab was added on 2026-07-23 (run order, every source and how
each is actually reached, metadata, scoring, watchlist query, passport
signature, payment, limits), and
gh-pageswas republished, so the live site is current. Two things that page now states publicly are worth carrying into the write-ups if they are not there yet: the web pipeline still runs the non-canonical deduction scorer, and the catalogue's confidence scores are researched by hand rather than computed. - The
ghtoken has noworkflowscope. Any push touching.github/workflows/*in an ETC repo was rejected outright. It forced a redesign inercf(the icon href is relative so no build-time rewrite is needed, which is the better fix anyway). Resolved: the active token now carriesworkflow, which unblocked pull-request CI (UPD-002) and the Node pin (UPD-007). - ethicaltechlab.org did not resolve. The live site answered on
https://ethical-tech-colab.github.io/website/; the apex domain returned
nothing when tested on 2026-07-23. Could be local network rather than DNS,
but worth confirming the custom domain is still pointed and the CNAME set,
since the site's
metadataBasenames it. - provenance-search's Pages site is only a redirect. What GitHub serves is a meta-refresh to a Railway app, so the URL dead-ends if that app ever lapses. Both pages carry the icon, but the redirect is worth revisiting — a static snapshot would survive Railway going away.
Added 2026-07-23. The reports on this site are hand-transcribed from papers in
the project repos, so a finding closed in a repo is not closed here until the
copy in src/content/publications/ is edited too. These are the ones still
genuinely open, i.e. not yet fixed anywhere.
- ERUS reports no results (
erus.ts, and the paper inIndia-EvacSimulation). The report poses three research questions and answers none of them with a number: no worked scenario, no sensitivity curve values, no information-value ranking, no assignment matrix. The generator is seeded and deterministic, so one or two fully specified runs would fix it and would let the report answer its own questions rather than restate them. Backlogged in detail in that repo. Run it from the browser; the page's top-level code is DOM-bound and lifting the engine out is easy to get subtly wrong. - AI's Carbon Footprint: the thesis qualifier is never argued
(
ai-carbon-footprint.ts, thesis / S1 / S7). The claim that mitigation can cut the footprint "without hindering its development and role in advancing society" is the clause that makes the report more than a polemic, and nothing in the body defends it. Needs engagement with the rebound problem, which the report's own "inference dominates at scale" argument implies, and with the possibility that binding regulation slows deployment. Either argue it or drop it. - Digital Provenance Passport: extend the permitted-source list
(
arts-provenance-agent). The report and the source now both state the coverage bias plainly and name this as the first substantive extension. Adding the Getty Provenance Index, the German Lost Art Foundation, Interpol, and source-country heritage authorities changes what every run returns, so it needs validating against known cases rather than being bundled into a documentation pass. Once done,digital-provenance-passport.tssection 08 needs updating with it. - Diplomatic Simulator: the mixed-model comparison is n = 1
(
diplomatic-simulator.ts, Limitations). Rotating tiers across seats, replicating, and a blind second coding of the red-line audit are what would turn documented instances into rates. Backlogged in that repo. The site's copy already states what the comparison does and does not license, so this only comes back here if the numbers change.
Added 2026-07-27 from a hostile-but-fair peer-review sweep of every report,
looking only for high-risk credibility gaps: uncited quantitative claims,
figures that look fabricated or internally inconsistent, claim–citation
mismatches, misread law, and misattributions. Ranked most-severe first. These
are the ones a hostile expert could use to discredit ETC; fix in the source
repo and the src/content/publications/ copy.
- [FIXED 2026-07-27] After the Corridor: §05 figures verified and
re-sourced (
after-the-corridor.ts+ sourceREPORT.md, §05 financial-model). Each figure was checked against its primary source: the $3.2B→$900M and Uganda $150/$225M figures are confirmed verbatim and kept; the "$56–62B/$41B" benchmark was mis-stated and is corrected to the actual World Bank–UNHCR figure (almost $62B to reach the poverty line in a no-income scenario, ~$40B already met by earnings, ~$22B remaining), re-cited to Making Refugee Self-Reliance Work; Kakuma's 3.4% is re-sourced to the "Yes" in My Backyard? Kakuma report; and Colombia's unsupported "500,000 / minimal host impact" phrasing is replaced with the verified ~30% income / ~10pp formal-employment effect. Dzaleka hero stat set to "53k to 60k". Original flagged numbers, for reference: (a) the "joint World Bank and UNHCR benchmark" of "US$56 to 62 billion annually, of which about US$41 billion is already met by refugees' own earnings"; (b) "UNHCR estimates ... complementary assistance costs would fall from about US$3.2 billion to roughly US$900 million a year" (a 72% collapse sourced only to a bare UNHCR self-reliance blog URL); (c) "Colombia's regularization of about 500,000 Venezuelans raised their incomes by about 31 percent" (the headcount mis-scales the underlying PEP study population; income effect uncited); (d) "Kakuma ... raised gross regional product by about 3.4 percent" and the Uganda "US$150 per refugee ... US$225 million" pair. Fix: pin each figure to a specific source (title, year, page) or downgrade to an attributed estimate; remove any that cannot be located. Presenting these as facts the model merely "formalizes" is the single biggest exposure across the reports. - CERAI misreads the law its threshold depends on (
cerai.ts, §05 / §08 / thesis / stat band). Three checkable IHL errors an international-law reader would catch: (1) the 75% "Article 49 obligation" threshold is built from a prohibition — GC IV Art 49 prohibits forcible transfer and only permits evacuation as a narrow exception in occupied territory, it does not mandate it; (2) §08 labels GC IV "Articles 16 and 24" as protecting "children and the elderly," but Art 16 covers the wounded, sick, infirm, and expectant mothers, and no GC IV article specifically protects "the elderly" — the exact confusion the EvacSim report corrects for its sister project; (3) it cites AP I Art 78 for internal child evacuation, but Art 78 governs only evacuation of children to a foreign country. Fix: reword the Art 49 basis to "permits as an exception," stop calling 75% an "obligation," correct the Art 16/24 descriptors, and rely on AP I Art 77 + GC IV Arts 24/50 for internal child protection. - AI's Carbon Footprint: misattributed and outdated magnitudes
(
ai-carbon-footprint.ts, §04 / §02 / §03). (a) "Training LLaMA 3-70B generated an estimated 2,290 metric tons of CO₂" — the cited model card reports 2,290 t as the combined 8B + 70B total; the 70B alone is ~1,900 t. (b) "Wyoming, where 95 percent of electricity comes from coal" is overstated/outdated (EIA ~71–79% and falling), and it underpins the "10×" hero stat. (c) "an estimated 11,000 data centers globally (Minnix, 2025)" cites a source absent fromcitations(which lists Brightlio). Fix: correct the Meta figure to 1,900 t (or relabel 2,290 as the combined total), update the Wyoming share to the current EIA figure and recheck the 10× ratio, and reconcile the 11,000 citation. Note this file had a ~1000× arithmetic error once before — verify every magnitude. - [FIXED 2026-07-27] What Is Ethical AI: internal contradiction + a
misattribution (
what-is-ethical-ai.ts, §09 / §12). Both fixed in the site copy and the sourceREPORT.md: §12 now reads "twenty six other states" (28 total, matching §09), and §09 now says Bietti "analyzed" (not "named") ethics washing. Original detail below. (1) The Bletchley Declaration count disagrees with itself: §09 says "twenty eight countries and the EU" while §12 says "the United States, China, the EU, and twenty five other states" (27 + EU). The correct figure is 28 states + EU, so §12 is wrong — change "twenty five other states" to "twenty six." (2) §09 says "Elettra Bietti named ethics washing," but her cited FAccT 2020 paper coined ethics bashing; "ethics washing" is credited elsewhere. Reword to "analyzed ethics washing" or credit her with the term she actually coined. - HASTE stat band contradicts its own body (
haste.ts, stat band vs §08). The 0.84 stat label says "Parity arrives at ten per cent, where it reaches 0.91," but 0.91 exceeds the fully-supervised 0.88 — that is overtaking, not parity, and §08 correctly says "overtakes the baseline." Fix: change the stat label to "the fast route overtakes the fully-supervised baseline (0.91 vs 0.88)." - Provenance Search: hand-recomputable score doesn't add up
(
provenance-search.ts, §05 variables). In the section whose selling point is "the score can be recomputed by hand," with a 100 base and 30 points per custody gap, "Three take the score to zero on their own" is false (3 × 30 = 90, leaving 10; four gaps reach zero). Fix: change to "Three leave the score at 10" or "Four take the score to zero." - Digital Provenance Passport: the case count contradicts itself
(
digital-provenance-passport.ts, §06 / §07 / §08 / §13). §07 and §13 say "five real and well-documented cases," §08 says "not limited to the fifteen objects researched by hand," and §06 cites a sixth object (the Getty Bronze, score 26) not in the five-case list. Fix: reconcile to a single number and make sure every object referenced is covered by it. (Related to the existing source-list item above.) - EII: verify the INFORM weights stated as fact (
evacuation-inform-index.ts, §03). The report asserts flatly that INFORM Severity combines "31 core indicators into three weighted dimensions: impact at 20%, conditions of affected people at 50%, complexity at 30%." Wrong weights would undermine the tool's whole proxy-substitution argument. Fix: confirm the indicator count and dimension weights against the current ACAPS/JRC methodology and correct if they differ. - Diplomatic Simulator: stale round-count phrasing
(
diplomatic-simulator.ts, §04). Now that the simulator covers six scenarios, "The other three scenarios run three rounds" (written for four) contradicts the six-scenario framing even though the aggregate 133-statement figure still closes. Fix: change "other three" to "other five." Lower confidence: §05 attributes a "paid to be accurate" detail to Tversky & Kahneman 1974 that is not clearly in that paper — drop it or resource it. - What Is Ethical AI hero stats (done 2026-07-27, confirm keep). The "4,000 years of ethics" and Gender Shades "34.7% / 0.8%" stats were removed as not insight-bearing and replaced with the Signpost "15% not safe" and ILO "$236B" figures, both drawn from the paper's own body. Revert if the editor prefers the original four.
Clean on high-risk quantitative claims (no action): ercf.ts,
mariupol-severity-model.ts, evacuation-simulation.ts, erus.ts,
forced-labor-structural-risk-index.ts, ai-models-research.ts,
ai-research-assistant.ts, vango.ts — each is heavily self-caveated and its
internal arithmetic reconciles. (ERUS's separate "answers no research question
with a number" gap is already tracked in §9 above.)
An expert-review pass over every page, run against the core user task for each surface, looking at usability heuristics, cognitive load and flow, and basic accessibility.
Method and its limits. This was read from source and built HTML, not from a browser session with real users, so it catches structural and heuristic problems rather than anything you would only learn from watching someone use the site. Three claims were checked empirically rather than assumed, and one of them came back negative — noted inline. Nothing here is a defect in the sense of "broken"; the site builds clean and every link resolves. These are friction points.
Core task: get oriented and reach the thing you came for.
The breakdown
- The intro curtain blocks the home page on every fresh load.
IntroCurtainrenders a full-screen overlay, setsbody.overflow = "hidden", and waits for a click — with a 5-second failsafe that dismisses it if no click lands. There is no persistence, so a returning visitor pays the toll every full page load, and someone arriving from search hits a logo before the content they were promised. This is a "user control and freedom" violation: the site decides when the visitor may proceed. - Its dismiss target is a
div, not a button.role="button"plustabIndex={0}plus a hand-rolled Enter/Space handler reimplements what a real<button>does natively, and does it slightly differently for assistive tech. - "Tap to enter" assumes a touchscreen. On desktop — where most of a conference or funder audience will see it — the instruction names a gesture that does not exist.
/aboutreturns a 404. For an organisation's site, About is the first place a new visitor looks to answer "who are you and why should I trust this". Any external link or search result pointing there hard-fails. See §7.- The newsletter block is a control that cannot be operated. A disabled email input next to a "Coming soon" button reads as a form, invites a click, and returns nothing. A dead control is worse than no control.
Actionable fixes
- Gate the curtain on first visit only: set a
localStorageflag on dismiss and skip it when present. OneuseEffect, no layout change. If it should stay on every load, cut the failsafe to ~1.5s so it never feels like a wait. - Add a visible skip affordance — a small "Skip →" in a corner — so the exit is discoverable rather than "click anywhere and hope".
- Swap the
motion.divformotion.button; drop the manual key handler and therole/tabIndexpair. Fixes the a11y semantics and clears theset-state-in-effectlint error in one edit. - Change the label to "Enter" or "Click to enter", or detect a coarse pointer and vary the word.
- Decide
/about(§7). If it stays hidden, at minimum make/aboutredirect to/teamrather than 404, so the URL is not a dead end. - Until Mailchimp is wired (§6), replace the newsletter form with a single
"Email us to be added" link to
site.email. Restore the form when the action URL exists.
Core task: find a demo and run it.
The breakdown
- On a phone there is no sign the rails scroll. The arrow buttons are
hidden sm:flex, and the rail hides its scrollbar (no-scrollbar). A rail can hold nine posters; a phone shows about two. Everything past the second is undiscoverable unless the visitor happens to swipe a region that looks like a static card. This is the single biggest flow problem on the site. - The primary call to action is invisible on touch. The "▶ Run" badge is
opacity-0untilgroup-hoverorgroup-focus-visible. Touch devices have neither. A mobile visitor sees a poster with a "Live" chip and no instruction that pressing it runs anything. - Two filter rows, no combined reset. Semester and Theme are independent, and clearing both means finding "All" in each row. After filtering into an empty result the visitor gets "No demos match those filters" with no button to undo it.
- The runner has no failure state.
DemoRunnerdrops the URL into an<iframe>with noonErrorand no timeout. Checked: none of the current hosts — Railway, Vercel, Netlify, GitHub Pages, D-ID — sendX-Frame-Optionsor aframe-ancestorsCSP, so nothing is broken today. But the day any host adds one, the visitor gets a blank white pane and no explanation, on the page the site is proudest of. sandbox="allow-scripts allow-same-origin"is not a sandbox. Those two tokens together let framed content reach its own origin and remove its own sandboxing. Low risk while every frame is CoLab-owned, but it is not providing the protection its presence implies.
Actionable fixes
- Show the rail's overflow on small screens: either reveal the scrollbar below
sm, or fade the right edge with a gradient mask wheneveratEndis false — an edge fade is the cheapest honest "there is more this way" signal. - Render the arrows at all breakpoints. They are already positioned and
already hide themselves when the rail fits, so dropping
hidden sm:flexis close to a one-word change. - Make the "Run" badge permanently visible on coarse pointers —
@media (hover: none) { opacity: 1 }— or simply always show it on cards that arelive. The scrim already guarantees it will read. - Add a "Clear filters" chip that appears only when a filter is active, and put the same action inside the empty state so the dead end has an exit.
- Give the iframe an
onErrorand a load timeout that swaps in a short message plus the "Open in new tab" link that already exists in the control bar. The escape hatch is built — it just is not reachable from the failure. - Drop
allow-same-origin, or dropsandboxentirely and say plainly in a comment that these are first-party frames. The middle position is the one that misleads.
Core task: find the report answering a question you have.
The breakdown
- The first shelf is the one most visitors cannot open.
publicationTopicsputs "Guidelines" first, and all seven guides areaccess: "internal", pointing at private repos. The catalogue opens on a row of things that turn the visitor away. - Same rail-discoverability problem as §10.2 —
PublicationsShowcaseuses the samePosterRail, so every fix there applies here. - The status filter is now two near-identical chips. Since every entry has
a
url, "All" and "Readable now" differ only by the seven internal guides. Two controls that produce almost the same list invite a pointless click. - 27 entries across 7 rails is a lot of vertical travel with no way to jump to a topic other than the filter chips at the top, which scroll away.
Actionable fixes
- Move "Guidelines" to the end of
publicationTopics, or split it below a "For CoLab members" rule so the public work leads. One array reorder. - Apply the §10.2 rail fixes — they are shared components, so both catalogues improve at once.
- Either relabel the pair to something with an obvious difference ("Everything" / "Public reports only"), or drop the status row and mark the guides visually in the rail instead.
- Make the topic chips sticky under the header, so the way to jump shelves stays reachable at any scroll depth.
Core task: understand what the cohort is working on.
The breakdown
- The archive's key instruction is far from the thing it describes. "Open a
project with a
+to launch its live demo" sits in the section intro; the cards it explains are below the fold. A card with no+gives no hint why. - Two different interaction models on one page.
PortfolioExplorer(expanding research questions) andArchiveExplorer(year-grouped cards) behave differently, and the page does not signal the shift. - Four archive projects still have no demo, repo, or write-up (§4), so they read as inert names — the visitor cannot tell "nothing here yet" from "you are missing the affordance".
Actionable fixes
- Move the
+explanation into the archive card grid as a one-line legend directly above the cards, and give demo-less cards a quiet "Write-up coming" marker so their state is stated rather than inferred. - Give the archive a visibly different section treatment — it already has
bg-surface/40; add the year as a sticky sub-heading so the grouping is legible while scrolling. - Close out §4 so the name-only cards get content.
Core task: see who is behind the work, and who backs it.
The breakdown
- Four org cards promise details they do not have. Every card in the
Partners & collaborators grid says "View details →", but 100x, Apne Aap
Women Worldwide, Gaia, and Grid Bank have an empty
about, and 100x, Gaia, and Grid Bank also have nourl. Clicking opens a modal containing a logo and a name. Now that all 19 organisations sit in one grid (2026-07-23), these dead ends are adjacent to rich ones, which makes them more obvious. - The page is very long — hero, founder, researchers, alumni, advisors, collaborators, then 19 organisations — with no in-page navigation.
- Five participants still have no bio (§7), so their cards and profile pages show no blurb while their neighbours' do.
Actionable fixes
- Suppress the "View details →" line when an org has neither
aboutnorurl, and make those cards non-interactive — a logo and a name, presented as such. Roughly three lines inOrgShowcase. Then fill the four blurbs (§3). - Add a sticky sub-nav for the team page (Founder · Researchers · Alumni ·
Advisors · Partners), mirroring
SectionTabson the portfolio pages. - Close out the missing bios in §7.
Core task: start a conversation.
The breakdown
- There is no contact form. The page's entire conversion path is a
mailto:link and two links to LinkedIn. This is the page whose single job is capturing an inbound enquiry. - Both channels have real drop-off. LinkedIn requires an account and a
login, which excludes plenty of institutional and government contacts;
mailto:does nothing useful for anyone on webmail, and on mobile it can open an unconfigured mail app. README.mdclaims aContactFormcomponent that does not exist insrc/components/. Anyone picking up the repo will look for it.
Actionable fixes
- Add a form. With a static export there is no server, so post to a third-party endpoint — Formspree, Netlify Forms, or a Google Form embed — and keep the email and LinkedIn links as alternates beneath it. This is the highest-value single addition on the site.
- Until then, make the email address the primary visual CTA rather than LinkedIn: it is the channel with no account requirement.
- Correct the component list in
README.md.
Core task: read a report and judge whether to trust it.
The breakdown
- No reading affordances on a very long document.
ScrollProgressexists as a component, but these pages carry no table of contents and no section jump, so a reader who wants section 07 must scroll for it. - Only one report offers a PDF (After the Corridor). For an academic audience that expects to download and cite, that is an inconsistent contract across the set.
- References are a flat list. With no back-links from the citation to the point it supports, checking a claim means scrolling away and losing place.
Actionable fixes
- Add a sticky table of contents from the section headings
ReportBodyalready receives — the data to build it is in hand. - Decide the PDF question as a set: either generate one per report or drop the affordance from After the Corridor, so the offer is consistent.
- Number the references and link each in-text marker to its entry, with a return link back.
The breakdown
- Muted text passes AA with almost no margin. Measured:
--mutedover--backgroundis 4.76:1 dark and 4.69:1 light; over--cardit is 4.63:1. The AA threshold is 4.5:1, so every one of these passes — but with under 6% headroom, and all fail AAA (7:1). Any future darkening of the token or lightening of a surface silently breaks compliance. - That token is used at very small sizes —
text-xs(12px) and, on the posters,text-[10px]andtext-[9px]. Small text at barely-AA contrast is the combination most likely to fail a real reader even while passing the automated check. - Hover-only affordances (§10.2) are keyboard-reachable via
focus-visiblebut not touch-reachable at all. - The intro curtain's non-native button (§10.1).
Actionable fixes
- Raise
--mutedopacity from0.52to about0.62dark and0.60to0.68light. That lifts every instance clear of the threshold — roughly 6.2:1 — and costs nothing but a slightly less recessive grey. - Set a floor of 12px for anything using
text-muted; for the 9–10px poster metadata, use--foregroundat reduced opacity instead so the contrast budget is spent where the text is smallest. - Apply the touch fixes in §10.2.
- Apply the button fix in §10.1.
Ranked by visitor impact against effort, not by section number:
/contactgets a form (§10.6) — biggest functional gap on the site.- Rail affordance and the touch-invisible Run badge (§10.2) — affects every mobile visitor to the two catalogue pages.
- Muted-contrast bump (§10.8) — one token, whole-site effect.
- Intro curtain: first-visit-only, real button, skip control (§10.1).
- Suppress dead "View details →" on the four empty org cards (§10.5).
- Move Guidelines off the front of the publications catalogue (§10.3).
An old-school flipbook of a report's original designed PDF, launched by a "Read
as book" button next to Download PDF on the report page, and surfaced on the
/publications catalogue by a "📖 Book" pill on the cover plus a "Read as book"
action in the sheet. Real page-curl via page-flip (StPageFlip), a client
component (src/components/ReportBook.tsx) that lazy-loads the library only when
opened; no pdf.js ships to the browser. Two-page spread on desktop, single page
on mobile; arrows / ← → keys / Esc.
Live for: After the Corridor (22pp) and What Is Ethical AI (46pp) — the two
reports with a designed PDF. Registry: src/content/publications/books.ts
(keyed by slug; bookForUrl() drives the catalogue).
How it's built. Pages are pre-rendered to WebP at build time by
scripts/render-report-pages.mjs (pdfjs-dist + @napi-rs/canvas + sharp) into
public/publications/<slug>/pages/, alongside a generated
src/content/publications/<slug>-book.ts manifest. The source PDF is vendored at
public/publications/<slug>/report.pdf. The script's REPORTS array lists the
slugs; run npm run render:book for all or node scripts/render-report-pages.mjs <slug>
for one.
To add a report: vendor its report.pdf under public/publications/<slug>/,
add the slug to REPORTS, run npm run render:book <slug>, add it to
books.ts, add a <ReportBook> to its report page, then npm run sync:static
and commit the images + manifest.
Open polish:
- No headless browser was available in the build session, so the live flip
interaction was not automated-tested — verify visually once in
npm run dev(build, types, and static export are all clean). - Consider a first-open hint/affordance that the corners are draggable.