From ed53bd90d9d29cfcd2e600180057b0b897766dfd Mon Sep 17 00:00:00 2001 From: prompt.ac/@jeffrey Date: Mon, 20 Apr 2026 23:12:46 +0000 Subject: [PATCH] are.na-annual: validator + primary-source swap proposal Adds validate-sources.mjs that reads the live channel and flags every Wikipedia link (52 of 68) plus fetches are.na search results to surface what other users are connecting for the same topic. The search endpoint is Cloudflare-gated for unauthed requests, so the 'nearby' column is empty until ARENA_TOKEN is exported. Drafts source-swaps.md — a full replacement table with primary URLs (UbuWeb, Monoskop, Fasola, Mela Foundation, Earle Brown Foundation, Noa Eshkol Foundation, Dance Notation Bureau, Terry Riley site, NYT Jalaiah profile, etc.). Also flags three wiki links that redirect to unrelated pages (Water Yam → yam tuber, Gahu → Iranian village, Renegade → K Camp song). Proposes blocks to ADD from the whistlegraph paper citations: Goodiepal El Camino del Hardcore, Dirt Magazine profile, Rhizome Longest Whistlegraph, Paper Rad, Schloss-Post RDP manifesto, Sex Magazine, CI essay. No channel writes yet — review swaps.md first. Co-Authored-By: Claude Opus 4.7 (1M context) --- gigs/are-na-annual-vol-8/source-swaps.md | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gigs/are-na-annual-vol-8/validate-sources.mjs | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 file(s) changed, 286 insertion(s)(+), 0 deletion(s)(-) diff --git a/gigs/are-na-annual-vol-8/source-swaps.md b/gigs/are-na-annual-vol-8/source-swaps.md new file mode 100644 --- /dev/null +++ b/gigs/are-na-annual-vol-8/source-swaps.md @@ -0,0 +1,118 @@ +# Source swaps — remove wikipedia, add primary sources + +current channel: 68 blocks · **52 are wikipedia** · 3 go to the wrong page entirely + +## critical fixes (wikipedia redirected to unrelated page) + +| # | current (broken) | swap to | +|---|---|---| +| 1 | `Renegade_(dance)` → goes to "Lottery (K Camp song)" | **NYT 2020 — Taylor Lorenz profile of Jalaiah Harmon**: https://www.nytimes.com/2020/02/13/style/the-original-renegade.html — the actual primary source for the story | +| 33 | `Water_Yam` → goes to "Dioscorea alata" (yam tuber!) | **Monoskop — George Brecht, Water Yam**: https://monoskop.org/Water_Yam — scans + bibliography | +| 31 | `Gahu` → goes to "Gahuiyeh, Kerman" (Iranian village) | **Ladzekpo / CNMAT archive** or **Mustapha Tettey Addy** – https://cnmat.berkeley.edu/library/cdr/ewa or drop for another drum tradition | +| 52 | `moma.org/s/ge/curated_ge/styles/list_ge/artists/1191/` → Page not found | **MoMA — Notations (1969) catalog**: https://www.moma.org/calendar/exhibitions/3282 | + +## graphic-score canon — swap to ubuweb, monoskop, foundations + +| # | wiki | primary | +|---|---|---| +| 38 | Treatise (Cardew) | **Monoskop — Cornelius Cardew**: https://monoskop.org/Cornelius_Cardew | +| 39 | Fontana Mix | **UbuWeb — Cage Fontana Mix**: https://www.ubu.com/sound/cage.html | +| 40 | Aria (Cage) | **UbuWeb — Cage Aria**: https://www.ubu.com/film/cage_aria.html | +| 41 | Concert for Piano and Orchestra (Cage) | **Edition Peters — Cage Concert**: https://www.edition-peters.com/product/concert-for-piano-and-orchestra/ep6705 | +| 42 | Variations I (Cage) | **UbuWeb — Cage Variations**: https://www.ubu.com/historical/cage/ | +| 43 | December 1952 (Earle Brown) | **Earle Brown Music Foundation**: https://earle-brown.org | +| 44 | Morton Feldman | **CNVill Feldman archive**: https://cnvill.net/mfhome.htm | +| 45 | Christian Wolff | **CNVill Wolff archive**: https://cnvill.net/mfwolff.htm | +| 46 | Artikulation (Ligeti) | **UbuWeb — Wehinger listening score video**: https://www.ubu.com/film/wehinger_artikulation.html | +| 47 | Metastaseis (Xenakis) | **Iannis Xenakis site / CIX**: https://www.iannis-xenakis.org | +| 48 | Sonic Meditations (Oliveros) | **Pauline Oliveros Foundation / Deep Listening**: https://deeplistening.rpi.edu | +| 49 | I Am Sitting in a Room | **UbuWeb — Lucier**: https://www.ubu.com/sound/lucier.html | +| 50 | In C (Riley) | **Terry Riley**: https://terryriley.net | +| 51 | Composition 1960 (La Monte Young) | **Mela Foundation**: https://www.melafoundation.org | +| 53 | Notations 21 | **Mark Batty / Theresa Sauer**: https://www.notations21.com (or author site) | + +## fluxus / event scores + +| # | wiki | primary | +|---|---|---| +| 32 | Grapefruit (Yoko Ono) | **imagine-peace.com / Ono Grapefruit scans on Monoskop**: https://monoskop.org/images/c/c7/Ono_Yoko_Grapefruit_1971.pdf | +| 34 | Dick Higgins | **Something Else Press archive / Estate of Dick Higgins**: http://www.dickhiggins.org | +| 35 | An Anthology of Chance Operations | **Monoskop**: https://monoskop.org/An_Anthology_of_Chance_Operations | +| 36 | Alison Knowles | **aknowles.com** (primary): https://www.aknowles.com | + +## vernacular / folk notation + +| # | wiki | primary | +|---|---|---| +| 24 | Shape note | **Fasola.org — Sacred Harp Musical Heritage**: https://fasola.org | +| 25 | Sacred Harp | **Sacred Harp Publishing Co.**: https://originalsacredharp.com | +| 26 | Tablature | **Lute Society of America**: https://lutesocietyofamerica.org (or guitar tablature primary source?) | +| 27 | Neume | **Gregobase — Gregorian chant notation**: https://gregobase.selapa.net | +| 28 | Jianpu | consider dropping, or: **Zhu Zaiyu / historical primer**; no strong primary online | +| 29 | Gongche notation | consider dropping, or a Kunqu / Peking opera archive link | +| 30 | Sargam | **ITC Sangeet Research Academy**: https://www.itcsra.org | + +## body / movement notation + +| # | wiki | primary | +|---|---|---| +| 14 | Labanotation | **Dance Notation Bureau**: https://dancenotation.org | +| 15 | Eshkol–Wachman | **Noa Eshkol Foundation**: https://www.noaeshkol.org | +| 16 | Benesh | **Royal Academy of Dance — Benesh**: https://www.royalacademyofdance.org/benesh | +| 17 | Kata | **JKA — Japan Karate Association / kata catalog**: https://jka.or.jp | +| 18 | American football plays | **Walsh's West Coast Offense playbook scans / NFL Coaches' resources** — or drop for a Bill Walsh interview | + +## sport / line + +| # | wiki | primary | +|---|---|---| +| 19 | Skateboarding | **Thrasher Mag**: https://www.thrashermagazine.com | +| 20 | Dogtown and Z-Boys | **Stacy Peralta / Z-Boys documentary**: https://www.imdb.com/title/tt0275309/ or https://www.dogtownskateboards.com | +| 21 | Surf break | **Surfline**: https://www.surfline.com | +| 22 | Yardage book | **StrackaLine — modern yardage-book publisher**: https://strackaline.com | +| 23 | Parkour | **ADAPT / parkour UK governing body**: https://parkour.uk | + +## instructional / craft + +| # | wiki | primary | +|---|---|---| +| 6 | Knitting abbreviations | **Craft Yarn Council standards**: https://www.craftyarncouncil.com/standards/knit-abbreviations | +| 7 | Crease pattern | **Erik Demaine — origami and folding**: https://erikdemaine.org/origami | +| 9 | Sewing pattern | **McCall's / Vogue pattern archive**: https://mccall.com | +| 10 | IKEA | **IKEA assembly instructions library**: https://www.ikea.com/us/en/customer-service/services/assembly | +| 11 | Lego | **LEGO building instructions archive**: https://www.lego.com/en-us/service/buildinginstructions | +| 12 | Julia Child | **WGBH — The French Chef / American Archive of Public Broadcasting**: https://americanarchive.org/catalog?q=julia+child | +| 13 | Japanese tea ceremony | **Urasenke**: https://www.urasenke.or.jp | + +## viral / social kin + +| # | current | primary | +|---|---|---| +| 2 | Harlem Shake (meme) | **Filthy Frank original video**: https://www.youtube.com/watch?v=384IUU43bfQ | +| 3 | Know Your Meme — Squidward (404!) | **Squidward tutorial original video** (YouTube search needed) | +| 4 | Pictogram | **Otl Aicher — Munich '72 pictogram archive**: https://www.designreviewed.com/otl-aicher-munich-1972 | +| 5 | ISOTYPE | **Otto Neurath / Gerd Arntz Web Archive**: https://www.gerdarntz.org/isotype | + +## additional blocks to *add* (from whistlegraph.tex citations) + +these are specific, real, less cliché: + +- **Goodiepal — El Camino del Hardcore** (ALKU 83, 2012) — https://alku.org/alku-83 or discogs +- **Jacob Ciocci — "The Butterfly Effect / Rules Set You Free"** (Whistlegraph Zine, 2023) — zine catalog page if exists +- **Asher Penn — Sex Magazine**: https://sexmagazine.us +- **Dirt Magazine — "What is a Whistlegraph?"** (2023): https://dirt.fyi/article/2023/09/whistlegraph +- **Rhizome — First Look: The Longest Whistlegraph Ever**: https://rhizome.org/editorial/2022/sep/13/first-look-the-longest-whistlegraph-ever-so-far +- **Feral File — Ten Whistlegraphs exhibition page**: https://feralfile.com/exhibitions/ten-whistlegraphs-thv +- **Schloss-Post — Manifesto for Radical Digital Painting** (2017): https://schloss-post.com/manifesto-radical-digital-painting +- **Creative Independent — "Drawing is the Best Videogame"** (2019): https://thecreativeindependent.com/weekends/drawing-is-the-best-videogame-by-jeffrey-alan-scudder +- **Paper Rad** (Jacob Ciocci): http://www.paperrad.org + +## execution plan + +1. `gigs/are-na-annual-vol-8/swap-sources.mjs` — read approved swaps, for each: delete old block from channel, post new URL with same description +2. keep positions stable — post in reverse reading order so nothing rearranges +3. text blocks (§9 framing, §6 Ono quote) are untouched — they're already primary + +## what the `nearby` validator can't tell us without a token + +are.na's `/v2/search/blocks` requires auth. once `ARENA_TOKEN` is exported, re-run `node validate-sources.mjs` and it will surface which URLs already have dozens of connections on are.na — those are the de-facto primaries. diff --git a/gigs/are-na-annual-vol-8/validate-sources.mjs b/gigs/are-na-annual-vol-8/validate-sources.mjs new file mode 100644 --- /dev/null +++ b/gigs/are-na-annual-vol-8/validate-sources.mjs @@ -0,0 +1,168 @@ +#!/usr/bin/env node +// Validate the blocks in "the-score-that-teaches-itself": +// - flag every Wikipedia link (we want primary sources) +// - for each block, search are.na for existing uses of the same URL +// and of the topic name — so we can see what other people +// are connecting to for the same idea (usually the real source) +// +// Usage: +// ARENA_TOKEN=... node validate-sources.mjs # all blocks +// ARENA_TOKEN=... node validate-sources.mjs --wiki # wiki only +// ARENA_TOKEN=... node validate-sources.mjs --json > report.json +// +// ARENA_TOKEN is optional but greatly raises rate limits. + +const SLUG = "the-score-that-teaches-itself"; +const TOKEN = process.env.ARENA_TOKEN; +const API = "https://api.are.na/v2"; + +const args = new Set(process.argv.slice(2)); +const WIKI_ONLY = args.has("--wiki"); +const JSON_OUT = args.has("--json"); + +const headers = TOKEN + ? { Authorization: `Bearer ${TOKEN}` } + : {}; + +async function j(url) { + const r = await fetch(url, { headers }); + if (!r.ok) throw new Error(`${r.status} ${r.statusText} — ${url}`); + return r.json(); +} + +function isWiki(url) { + return url && /wikipedia\.org/i.test(url); +} + +function hostOf(url) { + try { return new URL(url).hostname.replace(/^www\./, ""); } catch { return ""; } +} + +// Pull a short topic phrase out of a title like "Treatise (Cardew) - Wikipedia" +function topicOf(title) { + if (!title) return ""; + return title + .replace(/\s*[-–—|]\s*Wikipedia.*$/i, "") + .replace(/^\s+|\s+$/g, ""); +} + +// Search are.na for any blocks whose source matches the URL (or title) +// Returns an array of { url, host, count, sample: [{channelSlug, user}] } +async function searchSimilar(block) { + const out = { exact: [], nearby: [] }; + const url = block.source?.url; + const topic = topicOf(block.title) || block.generated_title || ""; + // 1) exact URL — search /search/blocks for the URL itself + if (url) { + try { + const q = encodeURIComponent(url); + const r = await j(`${API}/search/blocks?q=${q}&per=10`); + for (const b of r.blocks || []) { + if (b.source?.url === url) { + out.exact.push({ + id: b.id, + title: b.title || b.generated_title, + url: b.source.url, + connections: b.connections_count || 0, + }); + } + } + } catch (e) { out.err = e.message; } + } + // 2) topic phrase — find the most-connected non-wiki blocks for the same idea + if (topic) { + try { + const q = encodeURIComponent(topic); + const r = await j(`${API}/search/blocks?q=${q}&per=20`); + const seen = new Set(); + for (const b of r.blocks || []) { + const bu = b.source?.url; + if (!bu) continue; + if (seen.has(bu)) continue; + seen.add(bu); + if (bu === url) continue; + if (isWiki(bu)) continue; + out.nearby.push({ + url: bu, + host: hostOf(bu), + title: b.title || b.generated_title, + connections: b.connections_count || 0, + }); + } + out.nearby.sort((a, b) => b.connections - a.connections); + out.nearby = out.nearby.slice(0, 5); + } catch (e) { out.err = (out.err || "") + "; " + e.message; } + } + return out; +} + +function fmtReport(rows) { + const lines = []; + for (const row of rows) { + const flag = row.isWiki ? "🟡 WIKI" : "⚪ primary"; + const url = row.url || "(text)"; + const host = hostOf(url) || "—"; + lines.push(`\n#${row.position} ${flag} [${host}]`); + lines.push(` title : ${row.title || row.content?.slice(0, 80) || "(empty)"}`); + lines.push(` url : ${url}`); + lines.push(` desc : ${(row.description || "").slice(0, 100)}`); + if (row.sim) { + if (row.sim.exact?.length) { + lines.push(` ↳ already on are.na: ${row.sim.exact.length} exact block(s), top connections: ${row.sim.exact.slice(0, 3).map(e => e.connections).join("/")}`); + } else if (url) { + lines.push(` ↳ not on are.na (exact URL) — fresh`); + } + if (row.sim.nearby?.length) { + lines.push(` ↳ alternate sources people connect for this topic:`); + for (const n of row.sim.nearby) { + lines.push(` • [${n.host}] ${n.connections}× conn — ${n.url}`); + } + } + } + } + return lines.join("\n"); +} + +async function main() { + console.error(`fetching /channels/${SLUG}/contents …`); + const ch = await j(`${API}/channels/${SLUG}/contents?per=100&direction=desc`); + const blocks = ch.contents || []; + console.error(`got ${blocks.length} blocks${TOKEN ? "" : " (unauthed, rate limits apply)"}\n`); + + const rows = []; + for (const b of blocks) { + const url = b.source?.url; + const row = { + position: b.position, + class: b.class, + title: b.title, + content: b.content, + description: b.description, + url, + isWiki: isWiki(url), + }; + if (WIKI_ONLY && !row.isWiki) { rows.push(row); continue; } + if (b.class === "Link") { + try { + row.sim = await searchSimilar(b); + process.stderr.write("."); + } catch (e) { + row.simErr = e.message; + process.stderr.write("x"); + } + await new Promise(r => setTimeout(r, 400)); // gentle rate limit + } + rows.push(row); + } + console.error("\n"); + + if (JSON_OUT) { + console.log(JSON.stringify({ channel: SLUG, at: new Date().toISOString(), rows }, null, 2)); + } else { + console.log(fmtReport(rows)); + const wikiCount = rows.filter(r => r.isWiki).length; + console.log(`\n\nsummary: ${rows.length} blocks · ${wikiCount} wikipedia link(s) flagged for swap`); + } +} + +main().catch(e => { console.error("error:", e.message); process.exit(1); }); -- tangled.sh