Skip to content

The tools of the Archive: one definition of normalized text, a literalness check, and the importers - #214

Merged
DZPM merged 5 commits into
editionfrom
archive/1-tools
Oct 16, 2026
Merged

DZPM merged 5 commits into
editionfrom
archive/1-tools

Conversation

@DZPM

@DZPM DZPM commented Oct 15, 2026

Copy link
Copy Markdown
Member

Part 1 of 5 of the Archive, #213. The tools, with nothing of the archive itself: no page changes, no new content, and no template a reader reaches.

Everything here is a one-time importer or a check. The importers read an export of the Meetup, X, and YouTube accounts that is not in this repository, they were run once, and their docstrings say so: bin/import-talks in particular is not safe to run twice, and AGENTS.md records what a second run destroys. The archive they produced arrives in the four pull requests after this one.

What it adds

  • bin/canon.py, bin/slug.py, and bin/titlematch.py: one definition of normalized text, of the URL form of a title, and of the comparison form used to find one title inside another. An imported string is then consistent by construction rather than by a model behaving well.
  • bin/check-extraction: verifies an imported title and description against its source, character by character. Its test is seven recorded extraction runs, and one of them has to fail: a check that passes everything checks nothing.
  • The importers: bin/import-meetups, bin/import-talks, bin/import-videos, and bin/import-x-photos, plus bin/list-channel, which asks our YouTube channel what it holds and names anything the site does not list. That last one is the only tool here meant to be run again.
  • The extraction prompt under version control, with the reason it says nothing about typography.
  • bin/check-html-safety learns to read a content adapter, and bin/fit-sources caps an imported photograph at 1000px.
  • Two self-tests in CI, bin/canon.py --selftest and bin/check-extraction --selftest.

What it does not add

No check that depends on content this branch does not carry. A rule that rejects the old schedule model, or that checks a gallery, a venue, or the video inventory, lands with the content that makes it true: put it here and CI is red on arrival, which is measurable (the schedule rule alone gives 8 errors against edition today).

How to review

The diff is 29 files and no page of the site changes. bin/check-content, bin/check-rendered, and bin/check-html-safety pass on this branch, and the build is the same 113 pages as edition.

DZPM added 5 commits October 15, 2026 09:59
…atch

Three modules under bin/, one rule each, so that the import scripts that
follow cannot each carry a copy that drifts.

bin/canon.py normalizes text read from the Meetup export: one
deterministic transform in code, which never touches a letter or an
accent. A model told not to change the typography was measured against
the export: it changed the apostrophe anyway and corrupted an accented
letter in the same pass, so the rule cannot live in a prompt. The module
also strips Markdown and a leading time from a schedule label, which is
what comparing a source string against an extracted one needs. It has a
--selftest.

bin/slug.py makes an address out of a title: the file name of a meetup
and the id of a talk, which is the last segment of the URL of its page.
It drops the accents, which canon() must never do to a stored string.

bin/titlematch.py recognises a title inside another string that carries
it: the caption of a photo that quotes the talk it shows, or the title of
a video upload that names the talk it recorded. The two titles are two
honest records of one session at two moments, so the rule is tolerant
and documented, and it lives here once.
…fixtures

The import cannot parse 19 years of volunteer-written Markdown with one
parser, so a model reads each event description and returns the talks it
announced. A model can rewrite a word instead of copying it, and a
rewritten word on a published page looks like the real one.

bin/check-extraction compares every extracted title and description
against the normalized source, field by field, through bin/canon.py. A
curly apostrophe turned straight passes; a changed accent fails. That is
the boundary the archive needs: it holds Catalan, Spanish, and French.

bin/prompts/extract-talks.md is the prompt the model gets. It asks for a
copy, never a correction, and says nothing about typography, because the
normalizer owns that.

tests/extraction/ records the measurement of 2026-10-11: 9 events from the
export, 3 per format era, the talks each one announces read by hand, 7
real model runs, and the verdict the check has to give on each. One run
has to fail, so the selftest proves the check still rejects a changed
accent. The README of the directory says what each file is and why the
recorded runs keep their old key names.

pr.yml runs both selftests, and CONTRIBUTING.md lists five checks instead
of three.
Five scripts under bin/, each reading an export that is not in this
repository, so that every published fact of the archive can be traced to
a source:

- bin/import-meetups writes one page per monthly meetup out of the Meetup
  export: title, day, year, venue, registrations, source URL, and group.
  Each field is a copy of one field of the export, with canon() as the
  only transform.
- bin/import-talks writes the talks block of each meetup page from a
  checked extraction, and resolves a speaker name to a person record by
  the same name, ignoring accents and case. A name that resolves to
  nothing stays in speaker_names, which no template reads.
- bin/import-videos writes the video of a talk as a link of type video on
  its talk record, and the recording of a whole session as an entry of
  session_videos, from one normalized record per video of the channel.
- bin/import-x-photos stages the photos PyBCN posted live from one event
  on X: the files under deterministic names, a photos block to paste into
  the front matter, and a report for the person who curates the set. A
  photo the association only shared is listed and never imported.
- bin/list-channel reads the YouTube channel with yt-dlp and prints what
  the inventory does not hold, which is how a new video gets noticed.

AGENTS.md says in what order the imports run, that they ran once, and
what a re-run against content/ destroys. The bin/ row of its table names
the new scripts. README.md indexes the two decisions of
bin/import-x-photos: stage for review, never write content/, and never
import a retweeted photo.
…o at 1000px

bin/check-html-safety adds .gotmpl to the suffixes it scans. A content
adapter, content/<section>/_content.gotmpl, is a template Hugo runs
while it assembles the content, and it can write a page body through the
content key of AddPage, which goes through goldmark like the body of a
markdown file. No adapter is in the tree yet; the scan is ready for the
first one.

bin/fit-sources adds IMPORTED_PHOTO_CAP = 1000 for the photographs the
archive imports. The gallery never shows one wider than 900px and the
original is one click away in the post each one credits, so 1000 covers
that at full detail and leaves the repository a fifth lighter. Its
docstring also says that orpheus.png has been cut since the paragraph
about it was written: 1120x269 and 16 KB, and a dry run over the set
reports nothing.
LICENSING.md listed the Cookie Consent library by Osano among the
vendored files and excepted cookieconsent.min.js from the MIT grant.
Neither file is in the theme, so both sentences go.

README.md said the repository is 139 MB with blobs up to 5.9 MB. Both
figures move with every commit, so the paragraph now gives the command
that measures them (git count-objects -vH) and no number.

layouts/_default/_markup/render-link.html said that raw HTML no longer
renders because goldmark unsafe is off. It is on, for the two pre-Hugo
programmes pasted in as tables (AGENTS.md says so). The hook is still the
reason a plain markdown link opens in a new tab; the comment now says
why that is, without the false premise.
@DZPM
DZPM requested a review from a team as a code owner October 15, 2026 09:51
@DZPM DZPM self-assigned this Oct 15, 2026
@DZPM
DZPM merged commit 35f0558 into edition Oct 16, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants