MARC Holdings Workbench v0.49.0
Proof of concept — under active development. Check your output before loading it into the catalog.
One tool for MARC serials holdings. Upload a MARC file, find the patterns in its 866 statements, confirm what each part of a pattern means, and convert to structured 853 caption/pattern and 863 enumeration/chronology fields. Statements no pattern matches are converted by the standard parser.
No license is granted at this time; the repository is published for reference only while institutional intellectual property rights are reviewed. See NOTICE.md.
Portions derive from extract.py by Phani Chaitanya Pendyala (MIT). See THIRD-PARTY-NOTICES.md.
Questions: Matthew Codey, codey@usc.edu
What has changed
v0.49.0
2026-10-30
With a file, statements held or to check are put right on their records in step 3, where the rest of the record is in view; Edit and Split in step 2 open them there.
MARC Holdings Workbench Step 2 no longer lists a file's statements that are held or to check on each pattern card. Fixing them means reading the rest of the record, which a card doesn't show, and almost none depend on the pattern. On a 372-record export, 27 of the 28 statements listed across 17 cards came out the same whatever was decided on the cards. Each card now says how many it has ("3 held and 2 to check: put right on their records in step 3"), with a button that takes you to their records, and the line under the pattern count gives the totals, with "Show Needs attention" and "Show Something left out". A card still lists a statement the standard parser can't read at all, since that is usually a typo and is why its card asks for an answer.
MARC Holdings Workbench Edit and Split anywhere in step 2 open the 866 on its record in step 3: the record opens and the editor opens on that 866, with step 3 narrowed to the pattern's records to look at. Step 3's Edit now offers what step 2's did: "Also make this change on the other records with exactly this 866".
MARC Holdings Workbench A statement named in step 2, and the message after a fix, now give the record's identifier (the field chosen in step 1, such as the MMS ID) before its title, so it can be found in step 3 or in your ILS.
MARC Holdings Workbench Pasted statements are unchanged: they have no records and no step 3, so their cards still list everything and are edited in place.
v0.48.0
2026-10-29
Nothing on the screen or in your records changed. The page's code is now in files of its own, and a new code map says which file does what.
MARC Holdings Workbench The page was one 5,690-line file. It is now its layout (templates/tool.html), its styles (static/workbench.css) and eleven scripts in static/js/, one for each part of the screen: settings, step 1, the record list, step 2's cards, Edit and Split, the library, step 3 and so on. The page looks and works exactly as before; every check run on it gives the same result.
MARC Holdings Workbench New: docs/CODE-MAP.md, which says which file does what, follows each button (upload, Find patterns, Edit, Confirm, Convert all records, Download) through the files it sets going, and says where to look when a statement converts wrongly.
v0.47.1
2026-10-29
The advice to keep the 866 for wording MARC has no code for now says to check first that your system keeps it.
MARC Holdings Workbench Where a message suggests keeping the 866 to show a statement as written, it now adds that a system which rebuilds 866s from the 863s, as Alma does, may replace it. The Workbench doesn't yet link a kept 866 to its 863s the way MARC 21 provides for (the 863's "use textual display"); that waits until it can be tried in Alma, and HOW-IT-WORKS says so.
v0.47.0
2026-10-29
Wording MARC has no code for, like "Third Quarter" or "Buyers Guide", no longer costs the 863 its year, and the message says what MARC 21 lets you do with it.
MARC Holdings Workbench When a date has wording beside its year, the year is now written. "v. 2 no. 1-v. 3 no. 4 (1st Quarter 1980-4th Quarter 1981)" used to convert with no $i at all; it now gets $i 1980-1981, and only the quarters are left out. On a 372-record export this restores the year on 4 of the 8 statements with such wording.
MARC Holdings Workbench An issue dated across two years, like "no. 56 (2003:Dec./2004:Jan.)", gets both years, $i 2003/2004, as MARC 21's own example of this form records it. The months are left out and the record is marked to check. In a run, this also fixes an 863 that gave one year for several: "(Spring 1980-Fall 1981/Winter 1982)" used to be $i 1980 alone, and is now $i 1980-1981/1982. Two records of the 372-record export had this.
MARC Holdings Workbench The message for wording with no MARC code no longer says the subfield "takes MARC codes, not wording", which MARC 21 doesn't say. It now says what you can do, by kind. For a qualified season like "Late Summer": the code of the issue it is, if it is that issue (Summer is 22), or the words. For a quarter: there is no code, and in a quarterly the issue number usually says which quarter. For a named issue like "Buyers Guide": $o Title of unit in the 863, or a $z public note. For any of them: keep the 866 to show the statement as written. HOW-IT-WORKS has a new section on this.
v0.46.1
2026-10-29
Every pattern card that wants an answer now says "needs a decision", and a one-page quick start for cataloguers trying the Workbench for the first time.
MARC Holdings Workbench Every pattern card that wants an answer is now marked "needs a decision" in yellow, until you confirm or skip it: the same cards the Patterns step counts as still wanting one. Before, the mark showed only while a value had no meaning or only a suggested one, so a card could want an answer with nothing on it saying so. On a 372-record export the one such card showed only "not read".
MARC Holdings Workbench New: docs/QUICK-START.md, one page for a first try. It goes through the three steps in order (upload, answer what the Patterns step asks, check the settings, review the records under Needs attention, download the file and the log), names each button as the screen does, and says what each colour and label means.
v0.46.0
2026-10-16
The workbench can be used from the keyboard alone and with a screen reader: a file can be chosen without a mouse, and every button and tick box says what it is for.
MARC Holdings Workbench A MARC file can be chosen from the keyboard: Tab to the upload box and press Enter or Space. Before, it could only be clicked or dropped on.
MARC Holdings Workbench Escape closes an Edit or Split box without saving, in Patterns and in Convert. After Cancel, Close or Save, the keyboard is back on the button you were using, or the record or pattern you were on, instead of at the top of the page.
MARC Holdings Workbench For screen readers: the Reviewed, Keep patterns separate and Skip boxes under a record are read separately, with the record's title, where before they were read as one; Edit, Split, Copy and Close buttons say which statement, pattern or record they act on; Review buttons, record lines and filter chips say whether they are open or chosen; and Find patterns and the filter chips say what they found.
MARC Holdings Workbench The button that folds the Patterns step now reads "Hide patterns" instead of "Hide", to match "Show patterns".
v0.45.1
2026-10-16
Find patterns shows its cards in under two seconds on a 372-record file, where it took about seven.
MARC Holdings Workbench Find patterns is faster: on a 372-record export the cards now appear in about 1.6 seconds instead of 6.6. Nearly all the wait was the check that every pattern confirmed for you will always finish running, done one pattern at a time. It now checks them together, with the same safeguard for each. Importing a pattern library is faster for the same reason.
v0.45.0
2026-10-16
A pattern card's statements to look at are grouped by reason, each explained once, with the change or where reading stopped on each row.
MARC Holdings Workbench On a pattern card, "Statements to look at" is grouped by reason, and each reason is explained once above its statements instead of in a box on every one: "Months and seasons in one statement", "Not read by the standard parser", or a message shared only by statements that say exactly the same. What differs stays on each row, short: the change, such as February → Fall, which is where to split, or where reading stopped, which points at the mistake. Step 3 still shows the full message on each statement.
v0.44.1
2026-10-16
Clearing the pattern library starts over: Find patterns fills it again, even after uploading a file.
MARC Holdings Workbench Clear, in the pattern library, now starts over. Before, it remembered every cleared pattern as one you had removed, and that outlasted uploading a file, so clearing, uploading and finding patterns left the library empty. Now the next Find patterns confirms again every pattern it can read. A pattern you remove on its own is still not confirmed again, and the Patterns step now says how many were left out for that reason; Confirm on its card brings one back. Clear's question now says what it does, and that anything chosen on a card goes with it.
v0.44.0
2026-10-16
An open record in step 3 can be closed from its foot, and stays on screen while you work on it; every edit or split says whether it fixed the statement.
MARC Holdings Workbench An open record in step 3 has a Close button at its foot, beside Reviewed, Keep patterns separate and Skip. It folds the record back to its line and brings that line to the top of the screen, so after writing a note or ticking Reviewed there is no need to scroll back up, and the next record is right below.
MARC Holdings Workbench A record you are working on in step 3 no longer disappears under you. Fixing it, skipping it or ticking Reviewed while a filter such as Needs attention is on used to take it off the list at once; it now stays open, says it no longer matches, and leaves the list when you close it, with the next record taking its place at the top of the screen. Editing an 866 in step 3 also no longer folds step 2 above it, which moved the whole page.
MARC Holdings Workbench After any edit or split, on a pattern card or in step 3, a message at the bottom right says whether it worked: "Fixed", with how many 863s the 866 now converts to; "Saved. It converts, with something to check", with what; or "Saved, but still held", with the reason.
v0.43.0
2026-10-16
Each pattern card lists its statements to look at, every one, with its record and Edit and Split; buttons by kind, with counts, narrow the Patterns step to the held, to check, not read or left out.
MARC Holdings Workbench Each pattern card now lists the statements that are held, to check or not read — every one, not only the 25 examples — each with the record it is on, what happens to it and why, and Edit and Split beside it. A fixed statement leaves the list. "Show the records to look at" narrows step 3 to their records. Before, a card from a file only counted them, and every statement of a card is now counted, not the first 200.
MARC Holdings Workbench Under the pattern count, "Statements to look at" has a button for each kind, with how many statements and patterns: Held, To check, Not read, Left out. One shows only the patterns with that kind, each listing only those statements; "Show all patterns" goes back. They replace the sentence that gave these totals.
v0.42.0
2026-10-16
Held statements show where they come on the record, with Edit and Split beside them; a card says when the parser can't read a statement, and where it stopped; editing from a card no longer folds the Patterns step.
MARC Holdings Workbench A pattern card's preview of the record, and the record in step 3, now show every statement in the order its 866s come, each under the 853 it links to. A held statement sits where it comes, with its reason in orange and Edit and Split beside it, instead of in a "Held for review" block at the end; once fixed it converts where it stands. A pattern the record comes back to is headed again, "continued".
MARC Holdings Workbench A card whose statements the standard parser can't read says "N not read" and, even folded, where reading stopped on the first, with the usual causes: a comma missing between runs, a hyphen after a closed run, or a stray character. Edit fixes those; a statement written as meant is converted by what you say on the card.
MARC Holdings Workbench The example on a pattern card has Split beside Edit. After an edit or a split the Patterns step stays open, where before it folded away once its last question was answered.
v0.41.0
2026-10-16
A pattern never converts part of a statement; a list whose years go backwards is marked to check; the last run of a list can be left open in its years; a statement can be edited from its pattern card.
MARC Holdings Workbench A pattern no longer converts part of a statement. Where a statement is written as a list of runs the standard parser can't read (often a comma missing between two runs), a pattern could place only one run and set the rest aside as "Not encoded"; and with splitting on, a pattern could convert one piece while nothing read the others. Either way the 866 could then be removed with runs that were never written. Such a statement is now held, with nothing written, and the reason says what would have been set aside. "100% matched" on a card means only that the expression matches the wording; its preview says what would be written.
MARC Holdings Workbench A list of runs whose years go backwards from one run to the next, such as v. 21-26, 29-31, 33 (1921-25, 1938-41, 1932), is converted as written and marked to check, naming the two runs: a year typed wrong is the likeliest cause. Where a run inside a list is refused, such as a closed run left open (37-38-), the reason now names that run.
MARC Holdings Workbench The last run of a list can be left open in its years as well as its volumes: v. 1-3, 5-(1990-92, 1994-) converts, ending with $a 5- $i 1994-.
MARC Holdings Workbench A statement can be corrected from its pattern card, on step 2: Edit, beside the example, opens the whole 866 it comes from and saves the same edit step 3 makes, listed on the record and undone there with "Put back as uploaded". Where other records have an 866 that reads exactly the same, a box (unticked) makes the same change on them too. With pasted statements, Edit changes the line in the pasted text. A statement already corrected with Edit now still leads back to its record on its card.
v0.40.0
2026-10-16
Lists of months or seasons written under one year, and lists of volumes paired with lists of years, now convert; the pattern library can be seen, exported, imported and cleared as soon as the page opens.
MARC Holdings Workbench A list of months or seasons with the year written once at the end, such as (Mar, May, Jul 1995) or (Jan-May, Sep-Nov 1983), now converts to one 863 for each run, each with that year. These were held before, or written with the year alone. A list mixing months and seasons is still held, with its Split button, and months with no year at all are never written. No gap ($w g) is written between runs that follow straight on, such as Nov and Dec 1915.
MARC Holdings Workbench A list of volume runs paired with a list of year runs, such as v. 4-6, 9 (1951-53, 1956/57), now converts to one 863 for each pair, with short end years written in full (1951-1953). The two lists must be the same length, or nothing is converted from the statement.
MARC Holdings Workbench The pattern library is now under step 1, Holdings, and shows as soon as the page opens, so you can look at, export or clear a library kept from earlier in the visit, or import one saved earlier, before uploading a file or pasting statements. Clear now asks before it empties the library.
v0.39.0
2026-10-15
The Patterns step says which statements are held or to check, and no longer folds them away under "nothing to decide".
MARC Holdings Workbench Each pattern card now counts its statements that are held (nothing written, the 866 kept) and to check (converted, with something to look at first), beside the count of those with something left out to fit MARC; the sentence under the pattern count gives the totals. A pattern with a statement held or to check is no longer folded away under "nothing to decide": it goes in its own group, which starts open. Supplements and indexes keep their own group. With pasted statements, where there is no Convert step, each statement that doesn't simply convert is listed on its card with what happens to it and why, and one held for changing from months to seasons has a Split button there: the parts take its place in the pasted text.
v0.38.0
2026-10-15
Numbering ($v) can be set for one record, in "This record's 853".
MARC Holdings Workbench "This record's 853" now has Numbering ($v) beside Frequency ($w) and Issues per volume ($u). Whether issue numbers start again with each volume or run straight through is a fact about one serial, so it can be set for that record alone: Restarts each volume (r), Continuous (c), or (not specified) to write no $v on this record. Leave it at "As in Conversion settings" to use the file setting. As before, $v never goes on the first level of numbering, and the log lists it under "853 set by you".
v0.37.1
2026-10-15
A statement read by a pattern as more levels of numbering than an 853 has room for is held with its reason, instead of stopping the record with "could not check".
MARC Holdings Workbench Text that is really the values of an 863 written out, such as "2.1 54-62 1-1 1998-2006 21-21 g", could be given a pattern with every value answered Enumeration. That reads as eight or nine levels of numbering, and an 853 has room for six ($a to $f; five under the house convention). The record then stopped with "could not check". Such a statement is now held, nothing is written from it, and the reason says how many levels it read, how many have nowhere to go, and to say on the pattern which values are not numbering.
v0.37.0
2026-10-15
A serial that changes from months to seasons, or back, gets a second 853 from the change, and you say where the change falls: a change inside one 866 is held until you split it, and a change between 866s is marked to check.
MARC Holdings Workbench A statement whose chronology changes between months and seasons, such as "v. 19 no. 3-v. 20 no. 4 (September 1986-Winter 1987)", is now held, with nothing written and its 866 left in place. It used to convert to $j 09-24 under $j (season), which pairs September with nothing, and say nothing. An 853 gives months or seasons, not both, so the statement needs two 853s and two 863s, and only you know which issue the change falls at. 4 statements in the test collections are like this.
MARC Holdings Workbench Every 866 on a record now has a Split button beside Edit, and a held statement like the one above has "Split this 866 at the change". Write each part as a statement of its own, dividing where the change falls. The first part keeps the 866's notes; the others become 866s of their own right after it. The split is what the downloaded file carries, it is listed on the record and in the log as "Edited by you", and Undo the split puts the 866 back as uploaded.
MARC Holdings Workbench Where one 866 gives seasons and the next months, each still gets its own 853, and the statement where the new kind starts is now marked "To check", for you to confirm the change falls there. Where you made the change yourself by splitting an 866, it is said and not asked again. The log calls these "Held: months and seasons in one 866", "Check: months and seasons change" and "Split by you: months and seasons".
MARC Holdings Workbench A statement whose only season was left out to fit MARC, such as "v. 1-3 (1981-Fall 1983)", now gets an 853 with $j (season). It used to look like a month statement with less detail, and was filed under the next statement's month 853, or under a month 853 already on the record. Neither happens now: it has its own 853, marked to check.
v0.36.0
2026-10-14
A pattern's expression can be copied for the tool you will use it in: PCRE, JavaScript, Java, .NET, MarcEdit, Alma normalization rules or Oracle SQL for Alma Analytics, as well as Python.
MARC Holdings Workbench Above the patterns, "Write expressions for" chooses the tool you will paste an expression into: Python, PCRE (PHP, Perl, R, regex101), JavaScript, Java, .NET (C#, PowerShell), MarcEdit, Alma normalization rules, or Oracle SQL for Alma Analytics. Each card's expression line, its Copy button and "Copy all expressions" then give the expression in that tool's form, and a note under the menu says what the copy will and will not do there. The choice is remembered on this computer. The editable box inside a card still holds the expression as the workbench runs it.
MARC Holdings Workbench A copied expression now ignores capitals and matches a whole statement, as the workbench does when it uses one. Before, an expression pasted into another tool could match "v." and not "V.", or match part of a statement. In Python form it now begins (?i)^ and ends $.
MARC Holdings Workbench Oracle SQL can only find the statements that fit a pattern, not pull values out of them, and it takes at most 512 bytes. A pattern too long for it shows the reason on its card where the expression would be, with Copy turned off, and "Copy all expressions" gives the reason on that pattern's line. Of the 107 patterns in the project's three test collections, 62 fit.
MARC Holdings Workbench The MarcEdit form is for Find and Replace in the MarcEditor, where an 866 is a line such as =866 41$80$av.1 (1990)-. It finds the statement in an 866's $a, from just after $a to the next subfield or the end of the line, and never in another field or subfield. A $ in a statement is matched as MarcEdit writes it, {dollar}.
MARC Holdings Workbench The MarcEdit and Alma normalization rule forms have not yet been tried in MarcEdit or Alma. Try each on one record before running it across a file or a set.
v0.35.0
2026-10-12
Issues per volume (853 $u) can be set for one record, in "This record's 853".
MARC Holdings Workbench "This record's 853" now has Issues per volume ($u) beside Frequency ($w). How many issues make a volume is a fact about one serial, like its frequency, so it can be set for that record alone: a number such as 4 or 12, or var or und. Leave it empty to use Conversion settings, or type none to write no $u on this record. It follows the same rules as the file setting, and the log lists it under "853 set by you".
v0.34.0
2026-10-08
A value read correctly but left out because MARC has no place for it is now called "left out to fit MARC", shown everywhere it happens, and a setting decides whether such a statement converts, is held, or leaves its record as uploaded.
MARC Holdings Workbench Some values are read correctly and still cannot be written, because an 863 has no place for them: a season at one end of a range only, as in "(1981-Fall 1983)", a level at one end only, the "?" in "2016?", a date stated once for several runs. These used to be yellow notes among notes. They are now marked "Left out to fit MARC" in a dashed box on the record, the row says "1 left out", the log calls them "Converted, part left out", and a "Something left out" filter gathers them. Notes in braces and unexplained markers stay yellow notes. Nothing about what is written changes by default.
MARC Holdings Workbench On the Patterns step, a card whose statements lose something says "left out", and so does the line of a folded group and the summary at the top. A pasted statement no longer hides it under "nothing to decide".
MARC Holdings Workbench A new Conversion setting, "When something would be left out to fit MARC": convert it and mark it (the default), hold that statement and convert the rest of the record, or leave the whole record as uploaded. A record left as uploaded says so on its row, is under "Needs attention", shows what converting would have written, and has a "Left as uploaded" line in the log for each value, with its 866. Unlike strict, this applies to statements your patterns read too.
MARC Holdings Workbench A statement listing several runs, such as "34 no 3, 4 (Summer, Autumn 1990)", now takes the caption confirmed on its pattern. A pattern describes one run, so such a statement is read by the standard parser, one 863 per run; until now the caption confirmed for the bare number went unused, and the 853 kept "$a (*)" whatever you entered. It now reads "$a v. $b no.", and the pattern's preview shows it. A caption the statement prints is never replaced.
v0.33.0
2026-10-08
Each record has its own 853 settings: its frequency ($w), and captions for the levels its statements leave blank. Frequency now starts at "not specified".
MARC Holdings Workbench Frequency (853 $w) in Conversion settings now starts at "(not specified)". Before, it started at Annual, so every 853 said "$w a" unless you changed the setting, and changing it changed it for every title in the file. If you relied on Annual, choose it in Conversion settings or on each record.
MARC Holdings Workbench Each record now has a "This record's 853" panel below its holdings. Frequency ($w) can be set for that record alone, including "(not specified)". For each level its statements write as a bare number, which the 853 would declare "(*)", a caption can be given: it fills that level on every 866 of the record, whatever its shape, and on no other record. A caption a statement prints is never replaced. This is how "34 no 3, 4 (Summer, Autumn 1990)" and "39 no 1 (Spring 1995)", one serial written two ways, come to share one 853. What you choose is used wherever the record converts, the row says "853 set", and the log lists it as "853 set by you".
v0.32.0
2026-10-08
A statement that says it is a supplement or an index is held with its own reason, naming the field it belongs in, and a pattern no longer drops words silently.
MARC Holdings Workbench An 866 that says "Suppl.", "Supplement", "Special issue" or "Special no." describes a supplement, which MARC 21 records in 867, and one that says "Index" describes an index, recorded in 868. This tool does not convert 867 or 868 yet, so these statements are now held for that reason, not as one more statement it could not read. The record shows them under "Belongs in another field", its row says "1 belongs in 867" (or 868), "Needs attention" includes it, and the log calls it "Supplement: belongs in 867" or "Index: belongs in 868", so you can filter the spreadsheet to the ones to move. If a statement uses one of these words but is really part of the main run, edit the 866 to take the word out.
MARC Holdings Workbench Confirming a pattern no longer converts a supplement. Before, confirming the pattern for "v. 58 Suppl. (Sep 2003)", which arrived with everything filled in, wrote "$a 58 $i 2003 $j 09" with nothing to say "Suppl." had gone. A pattern made only of supplements or indexes now has nothing to decide, is never confirmed for you, and sits in its own fold on the Patterns step.
MARC Holdings Workbench When a confirmed pattern converts a statement the standard parser could not read, any words it matched but wrote into no field are now named on the record as something to check, such as the "?" in "?: 16" or "Ceased with". Those records now appear under "Needs attention"; before, the words were dropped without a warning.
v0.31.5
2026-10-08
Confirming a pattern with its suggested caption accepted as offered now clears "needs a decision".
MARC Holdings Workbench Where a pattern offers a reading as "likely, please confirm", such as the caption v. for the bare 39 in "39 no 1 (Spring 1995)", pressing Confirm pattern accepts it. But the card went on saying "needs a decision", and the row stayed highlighted, unless you had first changed something in it, so accepting the suggestion as offered looked as if it had not worked. The pattern had been saved and was used when converting. Confirming now clears the highlight and the pill whether or not you changed anything. Nothing about the conversion changes.
v0.31.4
2026-10-01
On a pattern, the settings that would change nothing are greyed out, with a note that the statement itself is where to correct them.
MARC Holdings Workbench A pattern's table lets you say what each captured value means, its caption and its level. But the standard parser reads every statement it can, and a confirmed pattern only supplies what the parser cannot: so for a value the statement itself names ("v. 1") or a year, changing these settings never changed the 853 or 863, and the screen did not say so. Those rows are now greyed out and marked "from the statement", and the note above the table says that to correct one you edit the 866 on its record. Only what a pattern can decide stays open: a number written with no caption, whose caption is yours to give, and every value of a statement the parser cannot read at all. Nothing about the conversion changes.
v0.31.3
2026-10-01
The tool is called the MARC Holdings Workbench throughout.
MARC Holdings Workbench The name at the foot of the page, in this list of changes and in an exported pattern library is now MARC Holdings Workbench, the name the screen already used, instead of MARC Serials Toolkit. Changes made to the original Converter and Pattern Detector, and to the first Workbench that joined them, keep those names. Nothing about the conversion changes.
v0.31.2
2026-09-30
A file set aside for pasted statements comes back with one click, and is named.
MARC Holdings Workbench Switching from a file to pasted statements no longer drops the file. It is set aside: still loaded, with your review decisions and the patterns found from it, but out of use until you come back to it. Step 1 names it ("example.mrc set aside") with a "Back to example.mrc" button, which brings back the file, its Convert step and its patterns without uploading again. Uploading a file still replaces it. The note shown when you type while a file is loaded now names the file, and the pasted text is no longer cleared when you upload. Patterns found from pasted statements are no longer linked to records in the loaded file that happen to read the same.
v0.31.1
2026-09-30
Holdings come from a file or from pasted statements, never both at once; patterns found from pasted statements are shown open.
MARC Holdings Workbench When you paste statements into step 1 instead of uploading a file, there is no Convert step, so the patterns are the only result to look at. After Find patterns they now stay open, with every group unfolded and each pattern's regular expression and Copy button in view. With an uploaded file nothing changes: when no pattern needs a decision, the step still folds to one line so Convert is in view.
MARC Holdings Workbench Step 1 is now either a file or pasted statements, not both. It used to be possible to upload a file and also paste statements: Find patterns then used the pasted ones while Convert worked on the file. Now the last one you choose wins. Uploading a file clears the text box. Clicking "Use these statements" sets a loaded file aside, and its records, Convert step and patterns go with it; uploading again brings a file back. If you type in the box while a file is loaded, a note says that "Use these statements" is how to switch.
v0.31.0
2026-09-30
Each 866's declared notation (its second indicator and $2) is now noted where it matters, without changing what is converted.
MARC Holdings Workbench An 866's second indicator says what notation its text is written in, and indicator 7 names it in $2 ("usnp" for the US Newspaper Program). The tool reads Z39.71 and still reads every statement the same way whatever is declared, so a wrong indicator or $2 costs nothing. What is new is a note, shown on the statement in yellow and written to the log: when an 866 declares a notation other than Z39.71 in $2; when it declares usnp but the text does not look like it; and when the text looks like US Newspaper Program notation (dates as [year:month:day]) but the 866 does not declare it. None of the 1,057 866s in the test export gets a note.
v0.30.6
2026-09-30
A list of single dates written as prose ("Jun. 17, 1880; Oct. 4, 1883") is held whole instead of recording only the last year.
MARC Holdings Workbench "Jun. 17, 1880; Oct. 4, 1883; Jun. 1887; Dec. 16, 1887" used to convert to a single 863, $i 1887, with the rest skipped: the comma in "Dec. 16, 1887" was taken for a gap between two holdings. The comma of a date is no longer read as a gap, and a statement made only of dates written this way is now held, with a note saying it is a list of single dates and that each would need its own 863, entered by hand. A lone "Jun. 17, 1880", which recorded just $i 1880, is held the same way. Nothing else in the test collections or the test export changes.
v0.30.5
2026-09-30
A statement ending with a full stop ("v.89,pt.1(1969)-v.96,pt.3(Dec.1972).") now converts instead of being held for the full stop.
MARC Holdings Workbench Some catalogues end each holdings statement with a full stop. The whole statement used to be held for it ("could not account for '.'"), and in a statement with two runs the second was skipped. One full stop at the end, after a closing parenthesis, a number or an open end, is now ignored. A full stop after a letter belongs to an abbreviation ("no.", "Dec.") and is still read as part of it; two full stops, or a note after one ("(Incomplete)"), are still held. In the test collections four statements now convert that did not; nothing that already converted changes.
v0.30.4
2026-09-30
A month written straight against its year ("Sept.1932") is read; before, the year was lost and a month could be recorded wrongly.
MARC Holdings Workbench Some catalogues leave out the space after an abbreviated month: "v.23,no.1(Sept.1932)-v.33,no.10(June 1943)". The date was not recognised, so both years were left out, and the end's month was written as if it were the month of the whole run ($j 06). It now converts to $a 23-33 $b 1-10 $i 1932-1943 $j 09-06, the same as with the space. Of all the statements in the test collections and the test export, this is the only one that converts differently.
v0.30.3
2026-09-25
A warning that needs a decision is now orange and headed "To check:", so it stands apart from warnings that are only for the log.
MARC Holdings Workbench On a record with more than one statement, a warning that makes a statement "to check" looked the same as a warning that was only recorded for the log, so you could not tell which statement the "to check" pill meant. Warnings that need a decision are now orange, with a thicker left edge, and begin "To check:". The reason a statement was held is orange too. Warnings that only go into the log stay yellow. The "held" and "to check" pills on each record are orange to match. Nothing about the conversion changes.
MARC Holdings Workbench A held statement now shows every reason it was held, not only the first. The first is often the general "No recognisable holdings ranges found"; the one after it says where reading stopped, such as "could not account for '// 1982//'", which is the part to clean up with Edit.
v0.30.2
2026-09-25
An 866 that holds the values of an 863 written out as text is now named as such, instead of "No recognisable holdings ranges found".
MARC Holdings Workbench Some catalogues have 866s like "2.1 54-62 1-1 1998-2006 21-21 g": the values of an 863 ($8 2.1 $a 54-62 $b 1-1 $i 1998-2006 $j 21-21 $w g) with the subfield codes gone. These are still not converted, because what each number counts was in an 853 that is not part of the text. But the record now says what the text looks like and what to do (rewrite it as a statement with Edit, or enter the 853 and 863 by hand), instead of "No recognisable holdings ranges found" and a note pointing at the wrong place. Nothing else changes.
v0.30.1
2026-09-25
An open end written inside the parentheses ("v.35 (2025-)") is kept, instead of being dropped without a warning.
MARC Holdings Workbench "v.35 (2025-)" used to convert to $a 35 $i 2025, a closed holding for a title still being received, and nothing said the open end had gone. It now converts to $a 35- $i 2025-, the same as "v.35(2025)-". A statement that gives a run and then leaves it open, such as "v.1-3 (1990-)", "v.1-3 (1990)-" or "v.1 (1990-1992)-", is now held with a note, because it does not say which part is still being received. Before, the first dropped the open end and the other two wrote a value an ILS would not accept ($a 1-3-). None of the statements in the test collections or the test export is written these ways, so nothing that already converted changes.
v0.30.0
2026-09-25
Dates written after the numbering without parentheses ("v.3-36 1963-1995") are now read.
MARC Holdings Workbench A statement that gives its dates after the volumes without parentheses, as older summary statements often do ("v.3-36 1963-1995", "v.40 no.4-6 2003.", "v.12 no.3 Mar. 1990"), used to convert to nothing and was held. It now converts to the same 853 and 863 as the statement with its dates in parentheses. The dates must come last and contain only years, months and seasons, so "v.1 2000 copies" is still held. So is "v.1-3 1990-", which does not say whether the run of volumes is open or the holding is. Statements already converting are unchanged: none of the 117 in the test collection or the 1,055 in the test export is written this way.
MARC Holdings Workbench Pattern headings keep the spaces the statements had: "VOLISS(CHRONYEAR)" is now "VOL ISS(CHRON YEAR)". Most headings in a file will look slightly different; what each pattern matches and converts is unchanged, and patterns you have already confirmed still apply. Dates written after the numbering without parentheses are headed with an ordinary hyphen ("VOL-VOL YEAR-YEAR"), not the long dash that divides the start of a holding from its end.
v0.29.1
2026-09-25
A year written before a volume ("1990: v.1") is read as its date, not as a level above the volume.
MARC Holdings Workbench "1990: v.1" used to convert to $a 1990 $b 1, treating the year as a level of numbering above the volume, and the 853 then called the volume the second level. It now converts to $a 1 $i 1990, and "1990: v.1-1992: v.3" to $a 1-3 $i 1990-1992. A year before an issue number ("2004 no. 3") is read as before, since some journals do number by year. A statement giving two different years for one volume, such as "1990: v.1 (1991)", is held rather than guessed at. None of the test collection's statements are written this way, so nothing already converting changes.
v0.29.0
2026-09-25
A range inside one end of the holdings ("nos. 1-3" at the start) is recorded by its first and last part, and the record says so.
MARC Holdings Workbench "v. 6 nos. 1-3-v. 14 nos. 10-12 (Mar 1978-Oct-Dec 1986)" used to write $b 1-3-10-12, which cannot be read, and lost the end year and the months. It now writes $a 6-14 $b 1-12 $i 1978-1986 $j 03-12: a compressed 863 records the first part held and the last, and a hyphen means "through". The record is marked to check, and its note says what to do if "1-3" was one combined issue rather than a range: write it with a slash in the 866 (Edit), and it is kept whole, as $b 1/3-10/12.
MARC Holdings Workbench Dates with a range at one end, such as "(May 1992-Mar-Jun 1995)", now keep both years and the months. Before, only the first year was written.
v0.28.0
2026-09-25
Holdings that Alma writes back from this tool's 853/863s now convert to the same 853/863s again, and a check proves it.
MARC Holdings Workbench Statements written the way Alma and Z39.71 write dates on their own -- "1990:Jan.-1994:Dec.", "2000:Spring/Summer", "2014:Nov. 7" -- now convert. They used to convert to nothing: they were mistaken for the year-first format ("1993: (1 [Feb])"), which the tool still reads as before. 42 statements in the test collection's export are of this kind once Alma has regenerated them.
MARC Holdings Workbench A statement like "(Feb, Jun, Aug 1998)" used to produce an 863 with nothing in it but its link number, and counted as converted, so "Remove each 866" would delete the 866 that held the holdings. It is now held for review, and the 866 stays.
MARC Holdings Workbench Smaller fixes found the same way: bare years ending in a comma ("1986-1988,") are read, with the gap; "v. 1 - 55" writes $a 1-55 without the spaces; and a range within one month of one year ("Oct 7-Oct 21, 1993") writes $j 10 rather than $j 10-10.
MARC Holdings Workbench For whoever maintains the tool: scripts/round_trip.py converts statements, writes the 866 Alma would generate from the result, and converts that again, reporting any difference. Run on an Alma export, it also checks its imitation of Alma against the 866s Alma itself generated.
v0.27.0
2026-09-25
A strict setting for the standard parser: convert a statement only if all of it can be read.
MARC Holdings Workbench Under "Use the standard parser for holdings no confirmed pattern matches" there is a new option: "Only where it reads the whole statement (strict)". Normally, when a statement goes beyond what the parser expects, it converts what it can and says what it left out. With strict on, that statement is held instead: nothing is written, its 866 stays, and the log lists it as "Not converted" with the reasons. It is off unless you turn it on. Statements your confirmed patterns match are not affected. On the test collection's 1,057 statements it holds 126 instead of 2, nearly all of them ranges where one end gives a month and the other does not.
MARC Holdings Workbench The Library of Congress's own 866 examples, from its MARC holdings documentation, are now kept as a separate set of test statements. They show how the tool does on holdings written outside the collection it was built on: of 7, 4 convert cleanly, 1 converts and says what it left out, and 2 are in the US Newspaper Program's notation and are held rather than misread.
v0.26.0
2026-09-25
Each pattern shows its expression, with a Copy button, and can show you the records it touches.
MARC Holdings Workbench Every pattern card now shows its expression under the heading, two lines at a time; click it to see all of it. "Copy" puts it on the clipboard exactly as it stands, including any change you have made in the box under "Expression and example statements". "Copy all expressions" at the top of the list copies every pattern at once, one per line, with its heading and number of statements, ready to paste into a spreadsheet.
MARC Holdings Workbench Each card can now show its records in the list of records below. "Show the records with this shape" lists every record holding a statement of that shape. For a confirmed pattern, "Show the records it converts" lists the records it actually converts, which can be fewer (a larger pattern may claim some first) or more (its expression may also match a similar shape). When the two differ, both are offered. The list is then filtered by a chip naming the pattern; press × beside it to go back to all records. Uploading a new file clears it.
v0.25.2
2026-09-24
A month written with a full stop ("Jan.") no longer makes a pattern of its own, and an uncertain year like "2016?" no longer says it was not converted when it was.
MARC Holdings Workbench "Find patterns" put statements like "v.1 (Jan. 1990)" and "v.2 (Jan 1991)" in two different groups, because the full stop after an abbreviated month was treated as a scrap of free text. The group with the full stop was headed "CHRON‹text›" and had to be confirmed separately. The full stop now belongs to the month, so both are one group. What each statement converts to is unchanged, and a pattern you confirmed for the old group still works.
MARC Holdings Workbench A statement that is only an uncertain year, such as "2016?", converts to the year as before. It no longer also carries a second warning saying nothing was converted. The warning that the question mark is not encoded remains.
MARC Holdings Workbench A note in braces on a statement like that, as in "2016? {gift}", was lost: the statement converted nothing and the note was mentioned nowhere. The year now converts and the note is reported, as it is on every other statement.
v0.25.1
2026-09-23
Ticking Skip no longer opens the record and moves the cursor to its note box.
MARC Holdings Workbench Ticking Skip now only marks the record skipped, as it did before 0.25.0. Opening the record and jumping to its note box got in the way when skipping several records in a row, and under "Needs attention" it did nothing, because a skipped record leaves that list. To write a reason for a skip, open the record: the "Your note" box is still at the bottom. The Skipped filter shows every skipped record together, so you can skip first and write notes afterwards.
v0.25.0
2026-09-23
Write your own note on a record -- a reminder for you or a colleague that goes into the log, never into the record.
MARC Holdings Workbench Opening a record now shows a "Your note" box at the bottom. Write a reminder for yourself or a colleague -- why the record was skipped, or what to check when you open it in your catalogue -- and it is saved when you click away or press "Save note". The note goes into the session log and nowhere else: unlike a $x or $z, it is never written into the record. Emptying the box removes the note.
MARC Holdings Workbench Ticking Skip on a record now opens it with the cursor in the note box, so the reason for skipping is easy to write down. Nothing asks you to: skipping without a note works as before.
MARC Holdings Workbench A record with a note is marked "note" in the list (hover to read it), and appears in the log even if nothing else is wrong with it, with the note as its first line under "Your note". Like everything else in a session, notes are kept until you upload a new file or the session ends -- download the log first if you want to keep them.
v0.24.2
2026-09-23
A skipped record no longer stays under "Needs attention".
MARC Holdings Workbench A record with a warning about the 853s already on it stayed under "Needs attention" after you marked it Skip, while other records left the list when skipped. Skipping a record means you are handling it yourself, so a skipped record is no longer listed there, whatever it carries. The warnings still show when you open the record, and the session log still lists it as skipped.
v0.24.1
2026-09-23
The review list shows at most 50 records a page.
MARC Holdings Workbench The "All records" choice in the review list's "Show" menu has been withdrawn: with every record of a large file on screen at once, opening and closing a record was slow. The largest page is now 50 records; 5, 10 and 25 are still offered, and 10 is still where it starts. If you had chosen "All records", the list now opens at 50 per page.
v0.24.0
2026-09-23
A session log: a spreadsheet of every record with something to look at, to take back to your catalogue or MarcEdit.
MARC Holdings Workbench Once you have converted anything, a "Download log" button appears beside "Download .mrc". It gives you a spreadsheet (a CSV file, which opens in Excel) with one line for each thing a record needs looked at: records you skipped, records kept because they already had 863s, 853s to check, statements that were not converted, statements converted with a note, corrections you made to 866s, and settings that were refused.
MARC Holdings Workbench Each line names the record three ways -- its place in the file, its identifier (the field you chose when uploading, 999 $b unless you changed it) and its title -- with the 866 statement concerned and what was said about it, so you can find the record again in your catalogue or in MarcEdit and fix it there. Sort or filter by the "What" column to work through one kind at a time. Records with nothing to report are left out. The log describes the same file the Download button gives you, including records you converted one at a time.
v0.23.1
2026-09-23
A file with an 866 that carries only a note no longer stops the records being checked, and one record the tool cannot handle no longer stops the rest.
MARC Holdings Workbench An 866 with no holdings statement -- one carrying only a note, such as "$z Current issues in reading room" -- stopped the whole file being checked. The list still appeared and "All" showed every record, but "Read by the parser" and "Read by a pattern" found nothing, and "Convert all records" failed. Such an 866 is now kept as it is, and the record's other 866s are converted as usual.
MARC Holdings Workbench If a record cannot be handled for any other reason, it is now marked "could not check", listed under Needs attention, left exactly as it was in the converted file, and the reason is shown when you open it. The rest of the file is checked and converted as usual, where before one such record stopped them all.
MARC Holdings Workbench If the records cannot be checked at all, the screen now says so above the list. Before, the only sign was every filter but "All" showing 0 records, which looked like a result rather than a failure.
MARC Holdings Workbench Uploading a new file now clears the Find box. Text left in it used to narrow every filter on the next file without saying so.
v0.23.0
2026-09-23
Correct an 866 in the Workbench: an Edit button beside each 866 re-checks the statement and regenerates its 853 and 863s.
MARC Holdings Workbench Opening a record now lists its 866 fields, each with an Edit button. Edit opens the field for correction, with a menu to choose what to change: the holdings statement ($a), which is where it starts, or the public ($z) or nonpublic ($x) note. "Save and check again" re-reads the corrected statement straight away: the record's 853 and 863s are regenerated, the review list is updated, and pattern detection runs again if you have run it. A typo such as "Fal 1995" no longer means leaving the Workbench to fix the record and starting over.
MARC Holdings Workbench The corrected 866 is what the converted file carries, so the record goes back to your catalogue fixed. Each correction is shown on the record -- "You edited 866 no. 3 $a: it read ... and now reads ..." -- and in the run summary, and the record is marked "866 edited" in the list. It is not listed under Needs attention: it is a change you made on purpose, not a problem. "Put back as uploaded" undoes a correction, and uploading a new file forgets them all.
MARC Holdings Workbench The holdings statement cannot be emptied; use "Put back as uploaded" to undo a change instead. An emptied note is removed.
v0.22.0
2026-09-23
853s and 863s already on a record are kept unless you ask for them to be cleared.
MARC Holdings Workbench A record that already had 863 fields -- added by hand, or by an earlier load -- had them written over by 863s generated from its 866s, even with "Clear existing 853 / 863 first" left unticked. The replacements could lose information the originals carried: on a real 372-record file, 38 hand-entered 863s on 10 records were replaced, and every gap marker ($w g) among them was lost. Nothing on the screen said so.
MARC Holdings Workbench A record with 863s of its own is now kept exactly as it came in. Its row in the review list says "has 863s · kept", opening it explains why, and the run summary counts it: "13 records already had 863s, kept as they were". Ticking "Clear existing 853 / 863 first" is how to have such records regenerated from their 866s instead, and the list and previews update as soon as you tick it.
MARC Holdings Workbench A record with an 853 but no 863s still takes its new 863s under that 853 when its holdings match it. When they do not, the tool used to write its own 853 over yours; it now adds a second 853 beside it, under the next linking number neither uses, and marks the record "853 to check" so you can decide which pattern is right.
MARC Holdings Workbench An 853 already on a record with indicators MARC 21 does not define, or two 853s sharing one linking number, is now reported on that record and listed under "Needs attention". Neither is changed.
MARC Holdings Workbench A statement that ends in a comma now records the gap it marks. "v.45(1988)," is how Alma displays an 863 with a gap after it ($w g), and the comma used to be read and dropped, so the 863 written from it had no gap and a display rebuilt from that 863 would lose the comma. A comma between two runs of one statement is read the same way -- "v.1(1990)-v.5(1994), v.7(1996)-v.9(1998)" records the gap after v.5 -- unless the numbering carries straight on. A semicolon records a break that is not a gap ($w n), as Z39.71 punctuates it.
MARC Holdings Workbench Notes on an 866 now go onto the 863s written from it: a public note ($z) such as "Incomplete", and a nonpublic note ($x). They used to be left behind. When one statement becomes several 863s, the note goes on the last of them, and the record says so, because the note does not say which part it belongs to.
MARC Holdings Workbench "Remove each 866 once it has been converted" no longer removes an 866 with something on it that has nowhere to go. Before, an 866's $z note was deleted with it and nothing said so. Now its notes are carried, and an 866 carrying anything else is kept, with a note on the record saying what.
v0.21.0
2026-09-22
An 853 that carries a count in $u is now written as able to compress or expand.
MARC Holdings Workbench When you fill in "Issues per volume" in Conversion settings, each 853 that takes the count in $u now has first indicator 2, "Can compress or expand", in place of 3, "Unknown". MARC 21 ties compression to $u and $v being present, and the tool already writes $v; the count was the missing piece. An 853 that does not take the count -- a serial numbered by volume alone, or one with three levels of enumeration -- stays at 3, so a single run can write both.
MARC Holdings Workbench A count of var or und leaves the indicator at 3, because a number that varies or is not known is not one compression can use. A first indicator you have typed yourself in the "853 indicators" box, and the house preset's 2, are left as they are: only 3 is replaced.
MARC Holdings Workbench Fixed: "Issues per volume" was left out of two places since it was added in 0.19. Opening a record showed its 853 without the $u, and "Convert this record" wrote the record without it, while "Convert all records" included it. So the same record came out differently depending on which button converted it, and the preview agreed with the one that was wrong. A record converted on its own, or previewed, now gets the $u "Convert all records" gives it. Records you converted one at a time with a count set are worth converting again.
v0.20.1
2026-09-22
The 853 indicator boxes in Conversion settings accept only the values MARC 21 defines.
MARC Holdings Workbench The two "853 indicators" boxes in Conversion settings wrote whatever was typed into every generated 853. A 4 or a 9 in the first box went into the file as the first indicator, and a box left empty wrote a blank, although MARC 21 defines only 0, 1, 2 and 3 for either indicator. Nothing on the screen or in the run summary said so.
MARC Holdings Workbench A value other than 0, 1, 2 or 3 is now refused, and the 853 keeps the preset's value instead -- 3 and 1 for the standard preset, 2 and 0 for house practice. The box turns red and a note beside it says so while you type, and the run summary names the value that was refused and the one kept in its place. Each indicator is checked on its own, so a mistyped second indicator does not cost you the first.
MARC Holdings Workbench An 853 that was already in your record before conversion is still kept exactly as it came in, indicators included.
v0.20.0
2026-09-22
The notes about the Leader above the review list can be hidden, and stay hidden in this browser.
MARC Holdings Workbench Each of the three notes about the Leader above the review list -- the encoding level, holdings that go past the level you are recording at, and records coded as single-part items (06 = x) -- now has a Hide button. On a file whose Leader values are the same defaults on every record, these came back on every upload saying the same thing.
MARC Holdings Workbench A hidden note is folded, not removed. It shrinks to one line that still gives its count -- "Hidden: Leader/06 coded as single-part item -- 36 records" -- with a Show button that brings the whole note back. Each note is hidden on its own, and it stays hidden in this browser for every file you upload, as the theme and text size are remembered. The "Leader & level" filter still finds the records whichever notes are hidden.
v0.19.0
2026-09-22
Choose how many records the review list shows at once: 5, 10, 25, 50, or all of them.
MARC Holdings Workbench A "Show" menu beside the record count sets how many records a page of the review list holds: 5, 10, 25 or 50 per page, or every record in the file on one page. Ten is still where it starts. The menu stays in view whatever you choose, so "All records" can always be changed back.
MARC Holdings Workbench Your choice is remembered in this browser, as the theme and text size are, so it is still set after a reload or a new upload. Changing it takes you back to the first page, as changing a filter does. The filters and the Find box work the same at every size: "All records" under "Needs attention" shows every record that needs attention.
MARC Holdings Workbench "All records" loads the whole file, however long it is. The server prepares at most 200 records at a time, so a longer file is loaded in parts rather than stopping at the two-hundredth record.
v0.18.1
2026-09-22
The count at the top of a conversion no longer includes the records you skipped.
MARC Holdings Workbench "Convert all records" counted the records you had marked Skip among the records it converted. Skipping one record of five read "5 records converted" beside "1 record skipped", although that record came out of the run exactly as it went in. The count now gives only the records the run converted -- 4 in that case -- and the skipped ones are counted once, under "records skipped".
v0.18.0
2026-09-22
Records converted one at a time now stay converted, and each can be downloaded on its own.
MARC Holdings Workbench Converting a record on its own used to throw away the record you converted before it. The file behind the Download button was rebuilt from your uploaded file each time, with only the record you had just converted written into it. Working through ten records a record at a time left a download containing the tenth and nine records exactly as they came in. Every record reported success, and the Download button stayed available throughout, so there was nothing on the screen to say the other nine had been dropped.
MARC Holdings Workbench Every record you convert now stays converted. The file is rebuilt from all of your decisions rather than the last one, so the download holds every record you have worked on, in the order they sit in your file.
MARC Holdings Workbench Each record you have converted now has a "Download this record" button of its own, beside "Convert this record". It gives you that one record as its own .mrc file, named after its identifier -- holdings_991234567890.mrc for a record whose 999 $b is 991234567890, or its place in the file if it has no identifier. For checking one record in a test load without running the whole file through.
MARC Holdings Workbench "Convert all records" now leaves a record you have already converted yourself exactly as you converted it, with the settings you chose for that record rather than the settings on the button. It reports how many it kept that way. Before, it redid every record and your own settings were lost.
MARC Holdings Workbench Skipping a record is still the stronger instruction: a record you have marked Skip comes out of a run exactly as it went in, even if you converted it by hand earlier. The run now says so -- it tells you how many records it set aside that you had converted individually, and unticking Skip and converting again puts your conversion back. The decision is held, not discarded.
MARC Holdings Workbench Uploading a new file clears every conversion decision, as it always cleared everything else. A decision is about a record in the file you made it on.
MARC Holdings Workbench Both download buttons were underlined, because a download is a link rather than something the page does and a link is underlined. Beside a button that is not, the pair read as two different kinds of control. They now look the same.
v0.17.6
2026-09-21
The 853 and 863 fields are written in their proper place in the record, instead of after everything else.
MARC Holdings Workbench A converted record put its new 853 and 863 fields at the very end, after the 866 they were generated from and after any local fields a system keeps there. A record that went in as 852, 866, 999 came out as 852, 866, 999, 853, 863. Valid, and wrong to anyone reading it: the field that defines the pattern sat after the textual holdings it explains.
MARC Holdings Workbench They now go where they belong — after the 852, before the 866 — with each 853 ahead of the 863s linked to it, and those in the order they were generated.
MARC Holdings Workbench Records that already had their fields out of order before conversion are left exactly as they were. Two records in the file this was reported from carry control fields out of sequence in the source; the new fields are placed correctly around them and nothing else is moved. Tidying somebody else's record inside a conversion is not this tool's business.
MARC Holdings Workbench Nothing about what is written changes — same 853s, same 863s, same values. Only where they sit in the record.
v0.17.5
2026-09-21
The browser tab now shows the site's icon instead of a blank page symbol.
MARC Holdings Workbench The tool had no icon, so a tab showed whatever blank marker the browser uses — which makes it hard to find among a row of open tabs. It now carries the same icon as the main site.
MARC Holdings Workbench It is served under both the name the page asks for and the name browsers request on their own, so bookmarking a page gets the icon too. That also clears the only error the browser console had been reporting on every page load, which was a request for the missing icon.
v0.17.4
2026-09-21
"Issues per volume" is written where issues are counted, and a serial with three levels of numbering is left alone rather than guessed at.
MARC Holdings Workbench The box asks for issues per volume, and on a serial numbered by volume and issue that is exactly where the number went. On one numbered by series, volume and issue it went beside the volume instead — saying how many volumes make a series, under a label promising something else.
MARC Holdings Workbench Three levels ask two questions at once: how many issues make a volume, and how many volumes make a series. MARC answers both by recording a number against each level. This tool collects one number, so it now writes none there and says why, rather than answering the wrong question with it.
MARC Holdings Workbench Nothing changes for a serial numbered by volume and issue, which is 857 of the 1004 statements in the file this was measured against and 89 of the 112 in the sample corpus. A serial numbered by volume alone still takes no number, because there is nothing above a volume to count against.
v0.17.3
2026-09-21
Recording at level 3 reports how many records carry more than that, once, instead of marking two thirds of them.
MARC Holdings Workbench Choosing level 3 — summary holdings, the first level of enumeration and chronology only — marked every record whose fields go further than that. On a file of detailed holdings that was 242 records of 372, which is not a signal: a marker on two thirds of a list tells you about the file, not about a record.
MARC Holdings Workbench It is now a line above the list, saying how many, like the two notes about the Leader beside it. The number was not visible anywhere before — the markers were spread over twenty-five pages, and the only total on screen belonged to a filter that also gathered records flagged for a different reason, so it showed neither figure.
MARC Holdings Workbench That filter is now called "Leader & level", which is what it gathers: records with something to note about their Leader, or about the level you are recording at. Its button finds them whatever the counts are, which is what matters for a file where only two or three records disagree.
MARC Holdings Workbench Recording at level 4 still reports nothing at all, because level 4 means every level a statement gives and nothing can exceed it. Nothing about conversion changes, and the Leader is still never touched.
v0.17.2
2026-09-21
The notices above the record list read as sentences again, instead of breaking into columns with gaps through them.
MARC Holdings Workbench A notice that mentioned a field by name — "06 = x", or an encoding level — came apart where the name appeared, leaving the sentence spread across the box in pieces with wide gaps between them. It was readable only with effort, and it affected the two notices about the Leader, the note about a missing identifier field, and the message about an unusable value for issues per volume.
MARC Holdings Workbench The cause was in the shared styling of every boxed message, which laid its contents out side by side rather than as running text. Any message naming a field in the middle of a sentence was split at that point. Messages that happened to be plain sentences were unaffected, which is why this only appeared once the tool started naming fields.
MARC Holdings Workbench Nothing but the layout changed. No wording, no counts, and nothing about conversion.
v0.17.1
2026-09-19
A run written as "(1960-66)" now records both years instead of losing the second.
MARC Holdings Workbench "v. 1-7 (1960-66)" converted to a field reading 1960, and the 66 — meaning 1966 — was dropped with nothing said about it. It now records 1960-1966. Nine statements in the file this was found in are written that way, and a run of years is exactly the thing a holdings statement exists to record.
MARC Holdings Workbench Two digits after a year can be ambiguous: "1990-12" might be 1990 to 2012, or December 1990. Months only run from 01 to 12, so anything above 12 is read as a year without hesitation, and anything that could be a month is left unencoded and reported rather than guessed at either way. "1999-00" reads as 1999-2000, because there is no month 00.
MARC Holdings Workbench This was found by a new check that reads a file and compares what each statement says against what was written from it, reporting anything that reached neither a field nor a warning. It found this on its first run. The sample corpus never contained a statement of this shape, which is why nothing had caught it before.
MARC Holdings Workbench Nothing else changes: the sample corpus converts exactly as it did — 90 statements cleanly, none with values lost.
v0.17.0
2026-09-18
A run of years written as a list no longer loses all but the first of them, and records coded as single items while holding serials are counted for you.
MARC Holdings Workbench A statement like "(1986-1988, 1993-1994)" converted to a single 863 reading 1986, and 1988, 1993 and 1994 were dropped — with no warning, nothing marked for review, and nothing to tell you it had happened. It now converts to two 863s, one for each run, with the break between them recorded. This is the thing this tool is least willing to do, and it was doing it: one statement in 1057 on the file it was found in.
MARC Holdings Workbench The same shape written with enumeration — "v. 24 nos. 2-5, 8-10 (Apr-Jul, Oct-Dec 1920)" — has always converted correctly. A list written as dates alone was the case nothing covered, because the list sits inside the parentheses with nothing in front of them to read it from.
MARC Holdings Workbench A statement that names its year once for the whole list, like "(Jan, Mar-May, Sep, Oct 1982)", is left exactly as it was: it still reports that it could not encode those dates. Reading it as a list would have filed three of those runs under a month in no particular year, which is worse than saying so.
MARC Holdings Workbench The Convert step now also counts records whose Leader calls them single-part item holdings while their holdings name a volume, an issue, or a span of more than one part. A single-part item is complete in one piece, so that coding cannot be right for them. Whether they should be serials or multipart items is a cataloguing decision, so the tool counts them and says nothing more.
MARC Holdings Workbench Like the encoding level, it is one line above the list rather than a marker on every row, because on a file migrated from a system that kept no MARC holdings it is true of nearly all of them. The Leader is still never changed.
v0.16.1
2026-09-18
The encoding level is reported once for the file instead of on almost every record, and "Needs attention" means something again.
MARC Holdings Workbench Version 0.13.0 marked a record whose Leader said one encoding level while you were recording at another. On a real file that turned out to be every record: an export of 372 holdings records, all of them declaring level 3, converted by a library recording at level 4, put the marker on 371 rows. A marker on almost every row tells you nothing, and it had also pushed all 371 records into "Needs attention", so that filter stopped being usable.
MARC Holdings Workbench The trouble was the question, not the counting. Whether your records' Leader matches the level you record at is a fact about the file — it is the same answer on every row — so it is now said once, in a line above the list: how many records disagree, what they say, and what you are recording at. Acting on it means changing those records in your catalogue, which is one operation there rather than a row-by-row job here.
MARC Holdings Workbench What stays beside a record is the question that actually differs from record to record: whether the fields being written go beyond the level you declared. Level 4 means every level the statement gives, so nothing can exceed it and recording at 4 now marks no records at all. Level 3 means summary — the first level of enumeration and chronology only — and on that same file 242 of 371 records carry more than that, while 129 genuinely are summary.
MARC Holdings Workbench "Needs attention" is about conversion again, and on that file went from 371 records to 11. The encoding level has a filter of its own beside it, so the records are still one click away — which is what matters for the file where only three of them disagree and finding those three is the point.
MARC Holdings Workbench The Leader is still never changed, and the test whose only job is to check that is untouched. Nothing about conversion changes.
v0.16.0
2026-09-18
You can state how many issues make a volume, and the tool writes it into the 853 where the standard puts it.
MARC Holdings Workbench A new box in Conversion settings, "Issues per volume". It fills 853 $u — the number of parts that make one of the level above, 12 for a monthly with annual volumes, 4 for a quarterly. The codes var and und are accepted where the number varies or is not known.
MARC Holdings Workbench It is written beside the caption it describes and nowhere else. On "v." and "no." it goes on the issue, because it says how many issues make a volume. A serial numbered by volume alone never gets one: there is nothing above a volume for it to count against, and the standard says so in as many words.
MARC Holdings Workbench Where a serial has three levels — a series, volumes within it, issues within those — the number you type is taken to mean the second level, volumes per series. The third level asks a different question, issues per volume, and is left alone rather than given the same answer.
MARC Holdings Workbench Left empty, nothing is written, which is exactly what every previous version did. That is the point: how many issues make a volume is a fact about how the serial is published, and a holdings statement does not state it. The frequency does not settle it either — a monthly with two volumes a year has six issues to a volume, not twelve — so the tool asks rather than guesses.
MARC Holdings Workbench Something that is not a count is refused with a note beside the box rather than written. A wrong number here would make a claim about the publication; no number simply makes none.
MARC Holdings Workbench Nothing else changes. The sample corpus converts exactly as before: 90 statements cleanly, none with values lost.
v0.15.1
2026-09-18
A note in curly braces no longer costs a statement its holdings.
MARC Holdings Workbench A statement like "1993: {Memorial Issue} (1 [Feb])" used to report that the note had been preserved and then convert nothing at all — the note was left in the text, the grammar met something it had no rule for, and the holdings went with it. A statement lost its holdings in order to say something about a note.
MARC Holdings Workbench The note is now set aside before the statement is read, so the holdings convert and the note is still reported as preserved but not encoded. This affected both ways the tool reads a statement, so the fix sits above both.
MARC Holdings Workbench "{lcub}" and "{rcub}" are left exactly as they are. Those are MARC's way of writing a literal curly brace rather than a note, and treating one as a note would delete a character somebody typed on purpose. The single statement in the sample corpus containing braces is of that kind.
MARC Holdings Workbench Nothing else about conversion changes: the sample corpus converts exactly as it did before — 90 statements cleanly, none with values lost.
v0.15.0
2026-09-18
When a file carries no 999 $b, the tool offers the fields that file does carry, instead of leaving a blank where the number should be.
MARC Holdings Workbench Version 0.14.0 read each record's identifier from 999 $b — Ex Libris Alma's MMS ID. A library on a different system has the number somewhere else, and the tool's only answer was to say it had not found one.
MARC Holdings Workbench Now it reads the file and offers what is actually in it. A field is proposed when it is on every record, appears only once in each, and has a different value on every one — the three things that make a field a name for a record rather than data about it. Each suggestion comes with a real value from your file beside it, because "991000485469603731" is recognisable to whoever uses those numbers and "999 $b" is not.
MARC Holdings Workbench You can also name a field yourself, written as 999$b or 001, or say to show no identifier at all. Something that is not a MARC field is refused with an explanation rather than accepted and shown as a column of blanks — a mistyped field and a field your records do not carry need different things from you, so the tool does not make them look alike.
MARC Holdings Workbench A field two records share is still offered, but marked. A title is the case that matters: two holdings of the same serial carry the same 245, so a title can be different on three records out of four — enough to look like a way of naming a record, and not enough to be one, because picking it would label two rows identically. Such a field now says "some records share one" beside it, and the list no longer claims that everything it offers is distinct.
MARC Holdings Workbench The change takes effect at once. The list is relabelled where it stands, without re-uploading the file and without disturbing the Reviewed, Skip or Keep-patterns-separate boxes you have already ticked.
MARC Holdings Workbench Your choice is remembered for the next file, because it describes your library's system rather than one export. Choosing to show no identifier is remembered too, so the tool does not keep asking a question you have already answered. Where the identifier is working, the field it came from is named quietly above the record list with a Change beside it.
MARC Holdings Workbench Nothing about conversion changes. The identifier is read and displayed only: it is never written to a record and never altered.
v0.14.0
2026-09-18
Each record on the Convert step now shows the number you look it up by, and a Find box searches the whole file for one.
MARC Holdings Workbench Holdings records do not usually carry a title — the title is on the bibliographic record, not on the holdings attached to it. So the Convert step was listing rows that read "Record 1", "Record 2", "Record 3", with no ISSN and the same location on every one. In a file of 372 records measured while this was built, nothing on screen distinguished one row from another except its position.
MARC Holdings Workbench Each row now shows the record's identifier, taken from 999 $b — in Ex Libris Alma, the MMS ID shown beside every record and used to key reports. It sits before the title, because on a holdings file it is the title, in the sense of being the thing that tells one row from another.
MARC Holdings Workbench A Find box above the filters searches the whole file, not the page on screen: identifier, title, ISSN, location, and the text of every 866. Part of a number is enough. It narrows whichever filter you have selected rather than replacing it, so "Needs attention" plus a search means both, and the count line and the pager follow along.
MARC Holdings Workbench If a file carries no 999 $b at all, the tool says so once, above the list, rather than drawing an empty space beside every row and leaving you to work out whether the file lacks the number or the tool failed to read it. Searching still works on everything else the records carry. Being able to name a different field is the next change.
MARC Holdings Workbench Nothing about conversion changes. No record is read differently, and the identifier is read and displayed only — it is never written, and never altered.
v0.13.1
2026-09-18
After updating the tool, refreshing the page is enough to see the new version. It used to need the server stopped and started again, without saying so.
MARC Holdings Workbench If you updated the tool while it was running, the page kept showing the old screen. The version number in the header updated, because that is read fresh every time the page loads — but the page itself was built once when the server started and then kept. So the header told you the update had arrived while you were looking at the version before it.
MARC Holdings Workbench This is how it showed up in practice. After an update that changed the Convert step to ten records a page, the screen still listed every record at once and the buttons underneath still counted in fifties — while the header read 0.13.0. Nothing was wrong with the update; the page being displayed simply predated it.
MARC Holdings Workbench The page is now rebuilt whenever its file changes, so a refresh is enough and restarting the server is no longer a step anyone has to know about. Nothing about conversion changes.
v0.13.0
2026-09-18
You tell the tool which level your library reports holdings at, and it writes that into every 863. A record whose Leader says something different is marked for your attention, and left alone.
MARC Holdings Workbench Conversion settings has a new choice, "Holdings reported at". Level 4 means detailed — every level a statement gives. Level 3 means summary — the first level of enumeration and chronology only. Whichever you pick goes into the first indicator of every 863 the tool writes.
MARC Holdings Workbench It starts on 4, which is what the tool wrote before this setting existed. Leaving it there produces exactly the same fields as version 0.12.5: the output of both sample files and all 117 corpus statements was compared byte for byte and is identical. Choosing 3 changes the first indicator of 134 863 fields across that same material and changes nothing else — not a caption, not a subfield, not a second indicator.
MARC Holdings Workbench Every holdings record also declares a level in its Leader, and the two should agree. When they do not, the record now shows an "encoding level" marker on the Convert step and appears under "Needs attention". Hovering it says what the record claims, what the tool wrote, and that nothing was changed. Both sample files declare level 3 throughout, so all 15 of their records with holdings are marked while the setting says 4, and none are once it says 3.
MARC Holdings Workbench The tool does not change the Leader, and that is deliberate. It is a statement your library makes about its own holdings, and correcting one on your behalf is a different kind of act from adding the fields you asked for. Set it yourself if the record should say what it now carries.
MARC Holdings Workbench Why you are asked rather than told. The obvious approach is to work the level out from the fields themselves — a statement with a volume and a month is detailed, one with only a volume is summary. That cannot be done, and the MARC documentation shows why. Every 863, 864 and 865 example in the five documents now kept under docs/marc was sorted by which subfields it carries: of the 129 that state a level, the four commonest shapes are marked both ways, and those four account for 89 of them. A volume and a year — the shape most of these statements convert to — is marked summary twenty-two times and detailed twenty-three times, and one field appears in two documents with the same bytes and a different level. The same holdings, reported differently by two libraries, and both right. So the tool asks.
MARC Holdings Workbench Changing the setting redraws what is on screen straight away, rather than waiting for the next reload, because it changes both the fields in every preview and which records are marked.
MARC Holdings Workbench No byte of any record's Leader is rewritten — there is a test whose only job is to check that.
v0.12.5
2026-09-17
Convert shows ten records at a time instead of the whole file, so the buttons below the list are no longer a long scroll away.
MARC Holdings Workbench The Convert step had a pager underneath the records, and it was telling the truth about which records it had fetched details for — but the list above it was showing every record in the file regardless. On a 320-record file that was the whole 320, about thirty-nine screens of scrolling to reach 'Convert all records' and 'Download'. The list now shows the ten the pager names.
MARC Holdings Workbench Ten a page rather than the fifty the pager used before. Fifty rows was still around eight screens.
MARC Holdings Workbench The line above the list now reads '29 of 320 match · 0 of 320 reviewed'. It used to say how many rows were on screen, which with a page of ten is only ever ten; what is useful is how much of the file the filter is showing you, with the pager saying where in it you are.
MARC Holdings Workbench The Patterns step pages the same way, but only the cards still wanting an answer from you, and only when there are more than ten of them. The confirmed, parser-read, skipped and too-complex groups are folded away already, so paging them would hide what is hidden.
MARC Holdings Workbench Nothing about conversion changes. The same records convert the same way, the filters still answer for the whole file rather than the page on screen, and moving between pages does not lose which records you have ticked as reviewed or skipped.
v0.12.4
2026-09-17
An 863 recording a single issue no longer describes itself as a compressed range. The code that says which it is now matches the field it sits on.
MARC Holdings Workbench Every 863 carries a code saying whether it records a range of parts — the first and last held — or a single part on its own. The tool was writing "compressed" on all of them, so "863 $a 8", one volume out of a list, claimed to be a range. Forty-five of the 137 fields the test collection produces were affected.
MARC Holdings Workbench "v. 19 nos. 1, 3, 5, 7-12 (Jan, Mar, May, Jul-Dec 1915)" shows both in one statement. The three single issues are now marked as single parts and "nos. 7-12" as a range, where before all four claimed to be ranges.
MARC Holdings Workbench Nothing about your holdings changes — no enumeration, chronology or caption is touched, and all 117 statements in the test collection convert to the same values they did before. What changes is one character that tells a receiving system how to read the field.
MARC Holdings Workbench A year written across the turn of one — "1996/97" — counts as a single year rather than a range, so "v. 12 no. 4 (Winter 1996/97)" is recorded as one part. It is one issue of one publication year, which is what the slash means.
MARC Holdings Workbench The MARC 21 documentation this is drawn from is now kept in the repository under docs/marc, so the reason for a decision like this one can be traced to the paragraph it came from.
v0.12.3
2026-09-17
A serial numbered by volume alone no longer gets a numbering-continuity code the standard does not allow there.
MARC Holdings Workbench The 853's $v says whether a level's numbering restarts when the level above it completes — issue numbers starting again at 1 with each new volume. MARC 21 allows it on any level of enumeration except the first, because the first level has nothing above it to restart against.
MARC Holdings Workbench The tool was putting $v on whichever level came last, so a statement with only one level put it on the first. "v. 6 (1935)" produced "853 $a v. $v r", claiming the volume numbering restarts against nothing. Eighteen of the 117 statements in the test collection were affected — every single-level one. Those 853s now end after the caption, as they should.
MARC Holdings Workbench A statement with two or more levels is unchanged. "v. 1 no. 2 (1990)" still gives "853 $a v. $b no. $v r", where $v describes the issue level and is correct.
MARC Holdings Workbench Nothing about enumeration or chronology values changes — no 863 is affected, and all 117 statements convert to the same holdings they did before. Only the pattern subfield on the 853 moves.
v0.12.2
2026-09-17
A record with a part of its statement the tool could not read is now marked as needing attention, instead of only carrying a warning you would have to open the row to see.
MARC Holdings Workbench Where a statement has several parts separated by commas and one of them cannot be read — "v. 4 (1990), 3rd series" — the readable part still converts and the part left out is still named. What changes is that the record now shows in "needs attention" on the Convert step, rather than looking converted with the explanation hidden inside the row.
MARC Holdings Workbench This is the same decision made in 0.9.6 for wording a coded subfield cannot hold: a warning only appears once you open a row, and nobody opens a row that looks finished. One path had been left out of that rule.
MARC Holdings Workbench It matters most where the part left out contains a number. "v. 4 (1990), lacks 7" and "v. 4 (1990), see also v. 9" both do, and nothing in the tool can tell a note about an issue you do not hold from one you do. That judgment needs a person, so the record is put in front of one.
MARC Holdings Workbench Nothing else changes. A statement the tool reads in full is not marked, and no statement in the test collection is affected — all 117 convert exactly as they did, with the same warnings.
v0.12.1
2026-09-17
A statement beginning with an ordinal — "50th Anniversary Issue" — is still refused, but the message no longer quotes a piece of a word that was never there.
MARC Holdings Workbench "50th Anniversary Issue (2017)" was refused with the message: Read '50t' but could not account for 'h Anniversary Issue (2017)'. The tool had split the word "50th" down the middle, so the message pointed at a place where reading never stopped. It now says only that no holdings ranges could be recognised, which is what actually happened.
MARC Holdings Workbench The same applied to any statement opening with a written ordinal — "3rd Series", "21st Century" — which were read as the values "3r" and "21s". None of them converted before and none convert now; only the explanation changes.
MARC Holdings Workbench Why a statement like this is refused at all has not changed: "50th Anniversary Issue" numbers nothing, so there is no volume or issue to record. A cataloguer who knows what the run contains can supply it by confirming a pattern on the Patterns step.
MARC Holdings Workbench A volume genuinely numbered with a letter is unaffected. "v. 4a" still records volume 4a, and "v. 12b no. 3" still records volume 12b, issue 3 — the trailing letter there is part of the number, which is why the tool allows one.
MARC Holdings Workbench Where the tool really does read part of a statement and stop, it still says so. "v. 58 Suppl. (Sep 2003)" is still refused with: Read 'v. 58' but could not account for 'Suppl. (Sep 2003)' — which is true, and tells you the supplement is the part it could not place.
v0.12.0
2026-09-16
The 853 now declares every level a statement shows the serial has, including one its own 863 cannot record a value for — and stops declaring a month where the statement never gave one.
MARC Holdings Workbench "v. 78 - v. 93 no. 3 (1981 - Sep 1996)" states a month. Because the month is at one end of the range only, a compressed 863 cannot record it — that is unchanged, and the value is still left out and named. What was wrong is that the 853 stopped declaring a month level at all, so the record described a serial that is not numbered by month, when the statement plainly says it is.
MARC Holdings Workbench Seven statements in the test collection now declare the month caption they were losing, and one declares a day caption. No 863 changes: not one value moves, and nothing that was recorded stops being recorded. The 853 gains a caption; the warning naming the value it could not place stays exactly as it was.
MARC Holdings Workbench The reverse case is fixed too. "v. 15 (1998 Buyers Guide)" was declaring a month caption because "Buyers Guide" sat in the slot a month would occupy. It is not a month, nothing could ever be written under that caption, and the 853 no longer offers one. The wording is still named as something the tool could not code, as before.
MARC Holdings Workbench Why the two are one change. The 853 sets out the whole structure a serial can have; the 863 records the values one holding pins down. Those are different questions, and the tool had been answering both with "did a value survive?" — so a month it could not place vanished from the map, and a phrase it could not code appeared on it.
MARC Holdings Workbench A note for anyone comparing output with an earlier version: an 853 caption with nothing under it in the 863 is normal and expected, not a sign something was lost. The tool's own corpus report used to count those as promises the record failed to keep; it now reports them as ordinary.
v0.11.2
2026-09-16
Starting the tool no longer prints a warning about the program's own code. Nothing about how statements convert has changed.
MARC Holdings Workbench On Windows, and anywhere else running Python 3.12 or newer, starting the tool printed a line of its own before the address: SyntaxWarning: invalid escape sequence '\s'. Nothing was wrong with your file or your holdings — the message was about a note inside the program — but a warning you cannot act on is one you learn to ignore, and the next one might matter. It is gone.
MARC Holdings Workbench Whether you saw it at all depended on which Python you run. On 3.10 and 3.11 the same message is suppressed, so the tool looked clean on one machine and not on another. That is why it went unnoticed for so long, and the suite now checks for it on every version rather than only where it happens to be printed.
MARC Holdings Workbench Nothing about conversion changes in this version. All 117 statements in the test collection convert to exactly the fields they did in 0.11.1 — 90 cleanly, 22 with a warning, 5 held for review, and none losing a value silently.
v0.11.1
2026-09-16
Confirming a pattern now says what your answer will change — the reading of a statement, a caption, or nothing at all — and stops asking where the answer would change nothing.
MARC Holdings Workbench Since 0.10.0 the standard parser reads every statement it can and a confirmed pattern supplies only what it cannot. The Patterns step had not caught up: it asked about every pattern in the same words, whether the answer decided how a statement was read or was discarded entirely. Each pattern now says which.
MARC Holdings Workbench Three things an answer can do. It can decide the reading — the parser writes nothing for those statements, so what you say is what converts them. It can supply a caption — the parser reads the statement, and your word goes where it could only write “(*)”. Or it can change nothing, when the statement names its own captions and the parser reads it in full.
MARC Holdings Workbench Patterns in that third group are no longer presented as work. They are folded away with the confirmed ones under “the standard parser reads on its own”. In the test collection one pattern of 44 was being asked about for an answer that was then discarded — “Series 1, v. 6 no. 1 (Summer/Fall 1992)”, which the parser reads as ser. 1, v. 6, no. 1 without help.
MARC Holdings Workbench A pattern whose answer decides the reading is no longer confirmed for you automatically, however confident it looks. The parser refuses those statements deliberately — it read part of the wording and could not account for the rest — so confirming one unasked writes holdings on a guess nobody checked. “v. 19 no. 2 Suppl. (1998)” is the case that showed it up: the pattern reads it as volume 19, issue 2, and the supplement, which is what the library actually holds, disappears into an ordinary 863. Those patterns now wait for you.
MARC Holdings Workbench The count at the top of the step says what is outstanding and why: “3 still want an answer — 1 decides how a statement is read, 2 supply a caption”, rather than describing them all as needing you to say what a value means.
v0.11.0
2026-09-16
The Converter and the Pattern Detector are now part of the one tool rather than separate sites. Everything they did is still here.
MARC Holdings Workbench There were three tools on three addresses: a Converter, a Pattern Detector, and the Workbench that joined them up. There is one now. Both of the other two had already been rebuilt inside the Workbench, so nothing they could do has been lost — the screens you used are the screens that remain, and every address the old tools answered on has a matching one here.
MARC Holdings Workbench The single-statement box is back: paste an 866 statement and see the 853 and 863 it converts to, with no file and no pattern needed. That was the Converter's front page and it is the quickest way to check one statement.
MARC Holdings Workbench One difference to know about. The old Converter removed the original 866 by default when a statement converted; this tool keeps it unless you ask for it to go. Keeping it is the safer default and the one the Workbench has always used, but if you were relying on the Converter's behaviour, tick 'Remove converted 866 fields' under Conversion settings.
MARC Holdings Workbench It opens at http://localhost:5003 — 5003 rather than 5000 because macOS uses 5000 for AirPlay Receiver. Start it with 'marc-serials' after installing, or 'python run.py' from a copy of the repository.
MARC Holdings Workbench Because there is one tool, there is one session and one place your uploaded file and pattern library are kept. Running the old Converter used to delete pattern libraries the Workbench was keeping; that cannot happen now.
v0.10.1
2026-09-16
A MARC file containing a record that cannot be read no longer fails with a server error. It is refused, and the record is named.
Converter A file with a damaged record in it — a bad length in the leader, a truncated directory, the sort of thing that turns up in a large export — failed to upload with a server error and nothing to say which record was at fault. The file is now refused with a message naming the position of every record that could not be read, so you can find and repair them.
Converter Refusing rather than converting is deliberate. A record that cannot be read cannot be written back out either, so converting the file would hand it back with that record missing — and the download is the copy you would load into the catalogue. It is the same rule already applied to a holdings statement the tool can only partly read.
Converter The file is checked before anything is stored, so a refused upload leaves the file you were already working on, and your pattern library, exactly as they were.
Holdings Workbench The same, and for the same reasons. Both tools now read a file through one piece of code rather than a copy each.
v0.10.0
2026-09-16
A confirmed pattern and the standard parser can no longer read the same statement two different ways. Five statements that produced nothing now convert, and eight stop declaring a month caption they never fill.
Holdings Workbench Until now a confirmed pattern read a statement by itself, from what its capture groups caught, and the standard parser read it a second way. Where they disagreed you got whichever one happened to run. Held against each other across all 141 statements in the test collection, the two agreed on 90 and disagreed on 10 — and on nine of those ten the pattern was the one that was wrong. The parser now reads every statement, and a confirmed pattern supplies what the parser cannot work out on its own.
Holdings Workbench What a pattern still decides is the part no parsing can settle. "v.1(1990)-5(1994)" carries a 5 that no caption reaches, so nothing in the statement says whether it is a volume or an issue; a cataloguer knows, and that is what confirming a pattern records. Captions work the same way: where a level is written as a bare number the 853 said "(*)", and the word you confirmed is now used instead. A caption the statement itself states is left alone — a pattern's "v." will not overwrite a "vol." printed on the piece.
Holdings Workbench Five statements that a pattern converted into nothing at all now convert in full: "1949: 1 (1-6 [Apr-Sep])", "1979: 1 (6-8 [Sep-Dec])" and "N 1994: (2 [Mar])" among them. "2018: ([Sum])" keeps its season, and "v.7/8(1996:Jul./Aug.)" keeps both its months; each was previously losing them on the pattern path only.
Holdings Workbench Eight statements were declaring a month or season caption in the 853 that their own 863 never filled — "v. 78 - v. 93 no. 3 (1981 - Sep 1996)" among them. A compressed 863 records the first and last part held, so a month at only one end of a range cannot be paired and is not written; the 853 now stops promising it.
Converter Nothing about the Converter's own output changes. It was already using the parser, and every one of the 141 statements converts exactly as it did before.
v0.9.9
2026-09-15
A statement that is only a year spanning the turn of one — "1996/97" — now converts instead of coming out empty.
Converter "1996/97" was producing an 863 with nothing in it, and a note saying the year could not be held. A year written across the turn of one is a single publication year and has been written out in full since 0.8.1 — everywhere except a statement whose only content is that year. It now converts to "$i 1996/1997", and "1999/00" to "$i 1999/2000".
Converter A range of them works the same way: "1990/91-1995/96" gives "$i 1990/1991-1995/1996".
v0.9.8
2026-09-15
Holdings written as two ranges either side of a slash are both recorded. One of them used to disappear, along with most of the other.
Converter "v.1(1990)-v.3(1992) / v.5(1994)-v.8(1997)" names eight volumes across seven years. It was converting to a single 863 reading "$a 1 $i 1990" — volume 1, 1990 — and the rest was gone. It now produces the two 863s the statement describes.
Converter The warning on that statement said nothing had been converted, while a field had in fact been written, and the record was not marked for review. So with "remove the 866" switched on, the original statement was deleted and the record left claiming holdings it does not describe. A statement the tool can only read part of is now refused outright, which is what the message always said happened.
Converter A slash only separates when there is a space on each side of it. A slash inside a value still means what it always did — a combined issue like "v.7/8", a combined month like "Jul./Aug.", a year spanning the turn of one like "1996/97" — and those are untouched.
v0.9.7
2026-09-15
Fixes a mistake in 0.9.6: a date range like "(Jan/Feb-July/Aug 1985)" was being refused and marked for review.
Holdings Workbench 0.9.6 taught patterns to notice a word attached to a season, so that "Late Summer" is not quietly recorded as Summer. It was reading the dash in a date range as part of that word: in "(Jan/Feb-July/Aug 1985)" it took "Feb-" to be a qualifier on "July/Aug". Statements that had been converting correctly lost their months and were marked as needing review. Ten statements in the test collection were affected — every "Apr-Jul", "Jan-Jun" and "Jul/Aug-Sep/Oct" in them.
Holdings Workbench What separates the two cases is whether the word before the dash is itself a month or a season. "Feb-" is, so the dash is separating two dates; "mid-" is not, so "mid-July" is still a qualified month and is still named rather than coded.
Holdings Workbench "Late Summer" is unaffected and still behaves as it did in 0.9.6: left out, named, and the record flagged for you to look at.
v0.9.6
2026-09-15
"Late Summer" is no longer recorded as Summer. Wording the tool cannot code is named, and the record is flagged for you to look at.
Holdings Workbench A pattern reading "(Nov/Dec 1994 - Late Summer 2002)" was writing the season as Summer and dropping the word "Late" without saying so. It may well be the Summer issue — or the serial may have an Early Summer too, in which case coding both as Summer merges two different issues. Nothing in the statement settles that, so the season is left out and named, and you are told, which is what the Converter has always done with it.
Converter Wording that a coded subfield cannot hold now marks the record as needing attention, not just a warning on the row. A warning only shows once you open a row, and nobody opens a row that looks converted. Two statements in the test collection are affected: the "Late Summer" one and "v. 15 (1998 Buyers Guide)", where a named issue sits where a date should be.
Holdings Workbench An ordinary season is untouched. A word only counts as a qualifier when it runs straight into the season or month; a dash or a bracket in front of it does not, so "(Spring 1990)" and "(Winter 1986 - Summer 1987)" convert exactly as before.
v0.9.5
2026-09-15
An issue number under a volume range is named rather than written, because a compressed 863 cannot say which volume it belongs to.
Converter "v. 40-45 no. 4 (1974-Apr 1979)" was converting to "$a 40-45 $b 4". A compressed 863 pairs its subfields position by position, so that field reads as no. 4 of every volume from 40 to 45 just as well as it reads as a run ending at v. 45 no. 4 — and nothing in the notation tells the two apart. The volumes are recorded and the issue is named as left out, with a note saying that writing both ends of the run out in full is what records it.
Converter This rule was already in place for a statement written with both ends — "v. 1 (1956) - v. 51 nos. 1-2 (2006)" has always dropped and named the issue. It was not reaching a statement written with one, like "v. 40-45 no. 4", where the volume range sits inside a single boundary. The two are now treated the same.
Converter Nothing is inferred. "v. 40-45 no. 4" is not read as starting at no. 1: the statement does not say so, and supposing it would invent a value.
Converter A statement where both levels give both ends is unaffected. "v. 40-45 nos. 2-5" reads back as one run, v. 40 no. 2 through v. 45 no. 5, and is written in full.
v0.9.4
2026-09-15
A combined issue like "no. 8/9" is read as one issue again, instead of being split in half and filed under the wrong levels.
Pattern Detector "no. 8/9" is one issue — a single issue numbered 8/9 — and patterns now capture it as one value. It was being split at the slash, which left half of every combined designation as a stray number for you to explain on the confirmation screen.
Holdings Workbench That split was doing real damage. In "v. 34 no. 8/9-v. 35 no. 23/24" the halves were not just lost but swapped: the issue 9 was treated as a volume and the volume 35 as an issue, and the field came out "$a 34 $b 8" — the end of the range gone and the issue cut in half. It now reads "$a 34-35 $b 8/9-23/24", the same as the Converter.
Pattern Detector A hyphen is treated differently from a slash, because it means something different. In "v.1-5(1990-1994)" it means volume 1 *through* volume 5 — two ends of a range, and you still confirm each. In "v. 23 no. 3-4-v. 29 no. 3-4" the statement is already divided into two, so the "3-4" in each half is issues 3-4 of that volume. Six statements in the test collection now convert the same way through patterns as through the Converter, and none changed for the worse.
v0.9.3
2026-09-15
A confirmed pattern now gives way to the standard parser for any statement holding several runs of holdings, not just a comma list.
Holdings Workbench A pattern describes one run of holdings. Where a statement holds several, the pattern kept the first and last values and set the rest aside — and for year-first statements like "N1984: (2 (1))M1985: 2 (2 [summer])" it was worse than that: the pattern claimed the statement and produced no 863 at all, where the standard parser produces the two it holds. These now go to the parser, as comma lists already did.
Holdings Workbench The test is no longer about commas. It asks the parser how many runs the statement holds, which is the thing that knows.
v0.9.2
2026-09-15
The summary after converting a whole file is now readable: figures first, then a table of which pattern read what.
Holdings Workbench The result of "Convert all records" was one long sentence with every pattern joined by commas — hundreds of characters on a small file and thousands on a real one. Worse, pattern names contain dashes of their own, so there was no telling where one entry ended and the next began. It is now a short line saying how many records were converted, a row of figures, and a table.
Holdings Workbench The figures lead with the question worth asking: of the statements read, how many did your own confirmed patterns handle, and how many fell through to the standard parser? Statements left for review, records you skipped, and statements a pattern deliberately left alone each get their own figure when there are any.
Holdings Workbench The per-pattern breakdown is a table — pattern, count, and a bar showing its share — sorted with the busiest first. It folds itself away when there are more than eight, so a large library no longer pushes the download button off the screen, and it scrolls rather than running down the page.
Holdings Workbench If none of your confirmed patterns were used, the summary says so outright instead of leaving you to count. That is exactly what a lost library looks like, and it was previously buried in the middle of a paragraph.
v0.9.1
2026-09-15
Uploading a MARC file no longer deletes a pattern library you confirmed earlier.
Holdings Workbench Your confirmed patterns were being stored alongside uploaded MARC files and cleared out on the same six-hour timer. So if you confirmed a library one day and uploaded a file the next, the upload deleted the library — and because the page had already read it, the sidebar went on showing the patterns while the server had none. Every record then converted with the standard parser, with nothing on screen explaining why. Libraries are now kept for thirty days.
Holdings Workbench Those thirty days are counted from the last time a library was used rather than the last time it was changed. Converting with the same patterns every week keeps them; only a library nobody has touched for a month is cleared.
Holdings Workbench Uploaded MARC files are still removed after six hours. That limit is there because the file is your data and should not sit on a server longer than the work takes; the patterns are your work, which is a different thing.
Holdings Workbench The pattern count in the sidebar is re-read from the server whenever you upload a file, so it can no longer show a number that conversion will not use.
v0.9.0
2026-09-11
Year-first statements no longer have "volume" and "issue" read into them, and an issue that was landing in the volume's subfield is put right.
Converter The year-first format — "1979: 1 (6-8 [Sep-Dec])" — says which number is the higher level and which is the lower. It does not say what either is called. The 853 was reading "volume" and "issue" out of it anyway; it now writes "(*)" for both, the same as anywhere else a level has no caption. If you know this format and want the words, set them once in the settings and they are used throughout.
Converter A real error was hiding behind those words. Where a block omits its higher level — "N1984: (2 (1))M1985: 2 (2 [summer])" — the lower number was sliding up into the higher one's place, so the 1984 issue went to $a and the 1985 issue to $b: the same level of the same serial in two different subfields, under an 853 that called them both "no.". Both now go to $b, where they belong.
Converter The volume that statement does state was being thrown away as well, with a note telling you to split records that "number differently". They do not number differently; one block just leaves a level out. It is now recorded, and the note is gone.
Converter A statement where no block states the higher level — "1993: (1 [Feb])" — still describes one level, not two. There is no sense declaring a level in the 853 that the serial does not have.
v0.8.9
2026-09-11
A level the piece does not caption is now written as having no caption, instead of being called a volume on the tool's say-so.
Converter "39 no 1 (Spring 1995)" captions its issue and not the number above it. The 853 read "$a v. $b no." — calling the 39 a volume because of where it sat, with nothing on the screen to say the word had been supplied rather than read. It is very probably a volume. That is not the same as the piece having said so. The 853 now reads "$a (*) $b no.", which is MARC 21 for a level with no caption on the piece.
Converter You can still name the level yourself: type a caption in the settings and it wins over everything. Bracket it — "[v.]" — if you want the record to show that you supplied it. The caption boxes now show "(*)" as what you get by leaving them blank, with v., no. and pt. offered as suggestions beside the grid.
Converter Holdings listed with no caption at all now convert. "8,13,15,17,19,20-(1982-1994)" becomes six 863s under one 853 — one per run, with the gaps marked and the last still open. It was refused before, on the grounds that nothing said whether those were volumes or issues. Nothing does; it turns out nothing needs to. The date range is named as left out, because it covers the whole statement and not any one run in it.
Converter A statement that is only a number — "106" — is still refused, because on its own it really does say nothing about what it counts.
v0.8.8
2026-09-11
A date that covers a whole statement is no longer copied onto each of its runs, and the pattern preview works again for statements you paste in.
Converter "v. 19 nos. 1, 3, 5 (1982-1994)" was writing 1982-1994 onto all three 863s, so each one claimed a single issue spanned twelve years. A span like that belongs to the statement as a whole, not to any one run in it. The issues are still recorded; the dates are named as left out, so you can add them by hand. A single year — "(1915)", or "1915/16" — really is every run's year and is still written to all of them.
Converter For the same reason, "v. 19 nos. 1, 3 (Jan 1915)" no longer refuses outright. January cannot be true of both no. 1 and no. 3, but the issues themselves are perfectly clear, so they are recorded and the date is named.
Holdings Workbench Pasting holdings statements into the text box instead of uploading a file no longer breaks the preview. The confirmation step was showing "renderPreviewPair is not defined" where the 853 and 863 fields should be — for every pasted statement, which is the quickest way to try the tool. It now shows what your pattern writes beside what the standard parser writes, as it was meant to.
v0.8.7
2026-09-11
An expression that never finishes is now stopped instead of hanging the server, and one warning no longer reads like a typo.
Pattern Detector A regular expression that runs forever is stopped after five seconds and reported, instead of taking the server out of service. This is easier to write by accident than it sounds — a repeat inside a repeat, such as (\d+)+, can take longer than the rest of your career on a statement that nearly matches — and until now the Test button had no way to give up. The message says what the likely cause is and how to fix it.
Holdings Workbench The same protection on the Test button and on the preview of a pattern you are editing.
Holdings Workbench A pattern whose expression does not finish is refused when you confirm it, rather than being stored and then hanging every conversion that used it. Your existing library is untouched when that happens — previously the screen would also have appeared to empty itself, which it no longer does.
Converter A warning read "so with no no level at the end it was left out" — the first "no" a negation, the second the caption "no.". Captions are now quoted and keep their period, and the sentence no longer needs the negation: "Only the end of this range gives a 'no.' level (1-2); a compressed 863 records the first and last part held, and there is nothing at the start to pair it with, so it was left out."
v0.8.6
2026-09-11
The Workbench now handles holdings written as a list with gaps the same way the Converter does.
Holdings Workbench Find patterns no longer breaks a list apart. "v. 19 nos. 1, 3, 5, 7-12 (Jan, Mar, May, Jul-Dec 1915)" was arriving at the confirm step as four separate shapes — "v. 19 nos. 1", "3", "5" and "7-12 (Jan, Mar, May, Jul-Dec 1915)" — two of which mean nothing on their own and still asked you to confirm them. It is one statement and is now shown as one.
Holdings Workbench A confirmed pattern no longer converts a list with gaps in it. A pattern describes one run of holdings: it kept the first and last values and set everything between them to "not encoded", so four runs came out as a single 863 holding two of the statement's twelve assertions. These statements are now read by the standard parser, which records each run as its own 863.
Holdings Workbench When that happens the conversion says so, naming the pattern that matched and why it was not used — a pattern you confirmed should never just quietly go unused.
Holdings Workbench A pattern you have marked to skip still claims these statements and leaves them alone. Skipping is your decision about what you will handle by hand, and it keeps working on every shape.
v0.8.5
2026-09-11
Holdings written as a list with gaps in it are read properly — one 863 for each run, and a break indicator saying where the gaps are.
Converter "v. 19 nos. 1, 3, 5, 7-12 (Jan, Mar, May, Jul-Dec 1915)" now converts to four 863s under one 853 — one for no. 1, one for no. 3, one for no. 5, one for nos. 7-12 — which is how MARC 21 records holdings with gaps in them. It was refused outright before, because reading only the first run and removing the 866 would have deleted the other three. Seven statements in the test collection are this shape, and all seven now convert.
Converter Each 863 before a gap carries $w g, the break indicator for parts that are lacking or a break whose cause is not known. Runs that follow straight on — "nos. 1, 2, 3" — carry nothing, because there is no gap to report. The other code, $w n for parts that were never published, is never written: nothing here can tell an unpublished issue from a missing one, and the wrong code is a claim about your collection.
Converter The two halves of the statement have to line up, or nothing is written. Three issue runs against two months means the statement was not understood, and holdings filed under the wrong dates is not something anyone downstream could catch. A year stated once at the end — "(Jan, Mar, May, Jul-Dec 1915)" — covers every run before it; a year stated per run is read that way instead.
Converter A comma inside a single date is left alone: "(Apr 18, 1996-Dec 1997)" is one date, not two, and is read exactly as it was before.
v0.8.4
2026-09-11
A range that names one level at its start and a different one at its end is no longer read backwards.
Converter "v. 12 no. 1-no. 6 (1990)" now converts to "$a 12 $b 1-6" — issues 1 to 6 of volume 12, which is what it says. It was producing "$a 12-6": volume 12 to volume 6, a range running backwards. The end of the statement writes only "no. 6", and the level a value belongs to was decided by its position alone, so "6" was read as a volume. Its caption is now read too, and settles it.
Converter The warning that came with it was also wrong, and is gone. It said the issue level had been left out for want of a closing value — while that closing value was the one sitting in the volume subfield.
Converter Where the captions cannot settle it — a range opening "v." and closing "pt.", which pairs nothing with nothing — the closing value is left out and named, rather than written into whichever subfield its position happened to fall in.
Holdings Workbench The same correction reaches statements converted through a confirmed pattern, where it was doing more damage: "v. 19 nos. 1, 3, 5, 7-12 (Jan, Mar, May, Jul-Dec 1915)" was producing "$a 19-3". It now reads "$a 19 $b 1-3". That is still not the whole statement — a list with gaps in it needs one 863 per run, which is the next piece of work — but it is no longer a claim the statement contradicts.
v0.8.3
2026-09-11
Longer patterns are allowed: the limit was turning away expressions the tool legitimately produces.
Pattern Detector The limit on how long a generated expression may be is raised from 2,000 characters to 4,000. Statements carrying several months are expensive to describe — "v. 19 nos. 1, 3, 5, 7-12 (Jan, Mar, May, Jul-Dec 1915)" needs 2,384 characters and is an ordinary discontinuous list, not anything exotic — so the old limit was setting aside patterns that were perfectly good. That statement now gets a pattern again, which is its only route to conversion: the standard parser declines it.
Pattern Detector The limit is still there, and the Test button still honours it: an expression past 4,000 characters is one nobody could read, edit or check, so the tool declines to offer it rather than handing over something unusable.
v0.8.2
2026-09-11
The detector no longer offers a pattern it would then refuse to test.
Pattern Detector A pattern whose expression comes out longer than the Test button accepts is now reported as too idiosyncratic to express, the same as an over-long statement, instead of being handed to you as a pattern that cannot be tested or saved. One statement in the test collection did this — "v. 19 nos. 1, 3, 5, 7-12 (Jan, Mar, May, Jul-Dec 1915)" — and had for some time; the standard parser reads it as before.
Pattern Detector The length limit is now measured on the expression itself rather than estimated from how many parts a statement has. The estimate was the problem: a month or season costs roughly seven times what a plain number costs, so a short statement full of dates could quietly exceed the limit.
Pattern Detector A pattern set aside now says which limit refused it. The card had one explanation because there had only ever been one limit, so a statement declined for length was told it was "25 parts long, past the point where a single expression can describe them" — which is not true when the limit on parts is 40.
v0.8.1
2026-09-11
A year split across the turn of one — "Winter 1996/97" — is read and recorded in full.
Converter "Winter 1996/97" now converts to $i 1996/1997 $j 24. A serial whose winter issue straddles the new year is numbered that way as a matter of course, and MARC joins the pair with a slash in $i exactly as it joins a combined month in $j. Until now the whole date failed to parse: "v. 12 no. 4 (Winter 1996/97)" produced a record with no year and no season at all, and the season was lost as quietly as the year.
Converter A range ending in a split year keeps both ends. "v.1(Spring 1996)-v.5(Winter 1996/97)" recorded only "$j 21" — which said the whole run was Spring — and now gives $i 1996-1996/1997 $j 21-24.
Converter The two-digit half is written out in full, taking its century from the first half and rolling forward where it has to: 1996/97 is 1996/1997, and 1999/00 is 1999/2000.
Pattern Detector A split year is one value rather than three. "Winter 1996/97" used to read as a season, a year, some text and a stray number, so a statement carrying one formed its own pattern and asked you about the "97". It now clusters with its ordinary siblings: "(Spring 1996)" and "(Winter 1996/97)" are one pattern to confirm, not two.
Pattern Detector Generated expressions are a little shorter, with no change to what they match — the whitespace between parts was being written twice. It matters because expressions are capped at 2,000 characters so that the Test button can always check them, and a chronology-heavy statement spends everything it has.
v0.8.0
2026-09-03
Day-level dates are recorded. Nothing in the test corpus is now lost without saying so.
Converter A date given to the day is now recorded to the day, in 863 $k under an 853 $k (day) caption. "1983: 5 (7-30 [Jan 28-Dec 29])" gives $i 1983 $j 01-12 $k 28-29. Until now the day was discarded from every bracketed date without a word — on one run-on statement in the test corpus that was fourteen dates gone from a single record, and it was the last thing the tools lost in silence.
Converter "Apr 18, 1996" keeps its day too. It was previously recorded to the month with a note saying the day could not be encoded; there is now a subfield for it.
Converter A day only one end of a range gives is still left out and named, exactly as a month is. "Apr 18, 1996-Dec 1997" records 1996-1997 and April-December but no day: a lone 18 in $k pairs with the other subfields positionally, so it would say the holdings end on the 18th as well as beginning on it.
Converter The caption and subfield settings now offer a day row, set to $k under the standard convention. The house convention has no day subfield — the local records it reproduces have no precedent for one — so a statement carrying a day converts without it and says which day it could not place, rather than quietly rounding to the month.
Workbench "Day" is now one of the meanings you can give a captured value on the confirmation screen, so a pattern can record day-level dates the same way the standard parser does.
v0.7.4
2026-09-03
A record numbered more deeply than any serial plausibly is now says so instead of looking ordinary.
Converter A statement read as four or more levels of enumeration is now flagged for checking. "8,13,15,17,19,20-(1982-1994)" is six separate holdings; read as a hierarchy it becomes $a 8 $b 13 $c 15 $d 17 $e 19 $f 20, which says the library holds one issue numbered six levels deep. That is not something lost, it is something invented, and it used to come out looking like any other converted record. Nothing can tell a genuinely deep serial from a list once the numbers are in hand, so the fields are still written — what has changed is that the record no longer passes in silence.
Workbench Records flagged that way are counted as "to check" beside the converted count, and appear under "Needs attention" — which until now meant only "nothing was converted". A record can need attention because of what was written, not just because nothing was.
Workbench Warnings about a converted statement now appear beside the 863 they describe, when reviewing a record. They were previously shown only for statements that produced no fields at all, so anything the converter said about a record it did convert never reached the screen.
v0.7.3
2026-09-03
The filters now answer for the whole file, and a record can send you back to the pattern that read it.
Workbench Fixed: the filters in Convert only knew about the fifty records whose previews were loaded, and every record past those passed every filter. "Needs attention" on a 120-record file showed the eight records that needed it and seventy-eight that did not. The counts behind the filters are now worked out for every record in the file, so a filter shows what it says it shows.
Workbench Paging now walks what the filter is showing rather than the file in order. With a filter on, "records 1-50 of 120" was answering a question nobody asked; it now reads "showing 1-50 of 120 matching", and disappears when everything matching already fits on one page.
Workbench Every record row now shows what it would produce, not just the first fifty.
Workbench A record read by one of your patterns has an "Edit this pattern" link beside it. It opens that pattern in step 2 wherever it is — unfolding the step, opening the group it sits in, and opening the pattern itself — because a mistake is nearly always spotted while reviewing records, and the place to fix it is the pattern.
Workbench Editing a pattern now puts the records it read back to "not yet reviewed", and says how many. A tick means somebody looked at this record's MARC; once the pattern changes that MARC is different and nobody has looked at it. Records the pattern never read keep their tick.
v0.7.2
2026-09-03
Set a shape or a record aside, and the tool leaves it exactly as it is.
Workbench A pattern can be skipped. "Skip these" on a pattern card means the statements it recognises are converted by nothing at all — no 853, no 863, and the 866 stays on the record. This is not the same as removing a pattern from the library: a removed pattern's statements fall through to the standard parser and are converted anyway, which is usually the opposite of what was wanted.
Workbench You can skip a shape before deciding what its values mean. "I cannot tell what this is" is a good reason to leave it alone, so the Skip button does not ask you to fill the table in first. Taking the skip off does ask, and says what is still missing — and the shape stays skipped in the meantime rather than quietly starting to convert.
Workbench A record can be skipped from its row in Convert. A skipped record is not touched at all: nothing converted, no 866 removed, and its existing 853/863 left alone even with "Clear existing 853 / 863 first" ticked. It comes out of a run exactly as it went in, for the ones you would rather catalogue by hand.
Workbench Skipped records have their own filter chip, and the review line counts them separately from the ones you have reviewed — set aside is not the same as dealt with.
v0.7.1
2026-09-03
The Patterns step folds up, and patterns that need nothing from you stay out of the way.
Workbench Patterns that were confirmed for you, and those too idiosyncratic to express as a pattern at all, now sit in a folded group instead of filling the page. On a file producing 44 patterns, 37 of them fold away and only the 7 asking you something are in front of you — the step went from about 4,600 pixels tall to about 1,300.
Workbench The whole Patterns step can be folded to a single line with the Hide button, the way the Holdings step already folds once it has your file. Folded, it reads something like "44 patterns · 36 confirmed · 1 too complex · 7 need a decision", so folding it never hides work still waiting for you — and Convert is right there rather than several screens down.
Workbench When a run finds nothing that needs deciding, the Patterns step folds itself, since there is nothing there for you to do.
v0.7.0
2026-09-02
Enumeration is no longer volume-then-issue: a title can be numbered any way it likes, to any depth.
Converter A title numbered by issue alone now converts. "no. 26 (May 1994)-no. 37 (May 2000)" produced nothing at all, because the tool could only read an issue that sat underneath a volume; it now records $a no. with 26-37, which is what MARC asks for — captions run from $a downwards in order of significance, and there is no rule that $a has to be a volume.
Converter Enumeration can go deeper than volume, issue and part. "v. 1 no. 2 pt. 3" already worked; a fourth, fifth or sixth level now works too, and a statement deeper than the convention has subfields for says so rather than losing the levels it could not place.
Converter The caption written into the 853 is the word the statement itself used. A statement that says "Bd." or "Heft" or "Report no." keeps it, instead of being renamed to the nearest of volume, issue and part.
Converter A leading series designation is no longer dropped. "Series 1, v. 6 no. 1 (Summer/Fall 1992)" was split at the comma into two unrelated holdings and the series was set aside with a note; it now converts whole, three levels deep, as $a ser. $b v. $c no.
Converter Two statements on one record that number in different ways can no longer be filed under each other's captions. "v.1(1990), no.5(1995)" would have written the 5 into the volume subfield, where anything reading the record afterwards would take it for volume 5; it is now left out and named, with a note that those statements belong on separate records.
Converter The caption and subfield settings now offer the first three enumeration levels by position rather than by name. The caption boxes start empty and show what an uncaptioned statement would get; fill one in only to override the word the statement used.
Workbench The confirmation screen asks what each captured value means — enumeration, year, or month/season — and, for enumeration, offers the familiar caption words as suggestions you can type over. You can also set which level a value sits at; left alone, it takes the level its position in the statement implies.
Workbench A value the pattern captured that nobody has decided about now marks the statement for review, instead of being noted and passed over. A value you deliberately set to "Not encoded" still passes, because that is an answer.
v0.6.4
2026-09-01
Fewer patterns to confirm, dates read to the day, and nothing but codes in a coded subfield.
Pattern Detector Months and seasons are now treated as the same kind of thing, and a combined chronology like "Jul/Aug" or "Winter/Spring" counts as one value rather than two with something in between. "(Sep 1944 - Aug 1945)" and "(Winter 1986 - Summer 1987)" are the same shape and used to be two patterns to confirm separately; across the test collection this took 55 patterns down to 44 and removed every case where one shape had been split. A pattern found from months will now also read the season a later record uses in the same place.
Pattern Detector A pattern's description now shows where it contains text the tool does not recognise, as ‹text›. "v. 58 Suppl. (Sep 2003)" reads "VOL‹text›(CHRONYEAR)" instead of looking exactly like a statement with no "Suppl." in it — two different patterns could previously appear on screen under the same description.
Converter A date written with a day is now read. "(Apr 18, 1996-Dec 1997)" recorded only "1997", claiming the holdings began that year; it now records 1996-1997 and April-December. The day itself is still not encoded — it has its own subfield this tool does not yet write — and is named on screen.
Converter Wording that is not a month or a season no longer reaches a subfield reserved for chronology codes. "v. 15 (1998 Buyers Guide)" wrote "Buyers Guide" into $j, and "Late Summer" produced the half-coded "11/12-Late Summer"; both are now left out and named, so you can record them by hand. Abbreviated seasons — Spr., Sum, Aut, Win — are recognised and coded rather than treated as wording.
Workbench "Split multi-range statements on top-level commas, semicolons or slashes" now starts switched off. Tick it when a file needs it.
Converter A bracketed group nested inside a year-first statement — the "(1)" in "N1984: (2 (1))" — is now named rather than dropped in silence. What it means is local to whoever wrote it, so the tool says it could not encode it instead of guessing.
v0.6.3
2026-09-01
Statements the parser can only partly read are now held for review instead of half-converted.
Converter A statement is now read whole or not at all. "v. 19 nos. 1, 3, 5, 7-12 (Jan, Mar, May, Jul-Dec 1915)" used to produce "$a 19 $b 1" — one issue of twelve, no months, no year — and the original 866 was then removed, so the rest of the holdings went with it. Statements like this are now held for review, and the screen says how far the reading got: "Read 'v. 19 nos. 1' but could not account for ', 3, 5, 7-12 (...)'". The same applies to a supplement designation sitting between the numbering and the date, as in "v. 58 Suppl. (Sep 2003)". Fewer statements convert as a result; none of them were converting correctly. Please re-check any file converted before this version for holdings that stop earlier than they should.
Converter A month or season given at only one end of a range is no longer recorded. "(1981 - Sep 1996)" wrote "$i 1981-1996 $j 09", which a catalogue reads as the run beginning in September 1981 — the statement never said that. Where both ends name one it is kept as a pair, as before. The value that could not be placed is named on screen either way.
Converter A combined volume is now read. "v.7/8(1996:Jul./Aug.)" matched only "v.7" and dropped the year and both months in silence; volumes now accept the same combined form issues always have.
v0.6.2
2026-09-01
A range now records both of its ends, and says which value it could not place.
Converter A range that begins and ends at the same issue now records both ends. "v. 41 no. 1-v. 43 no. 1" wrote "$a 41-43 $b 1", which reads just as well as issue 1 of each of volumes 41 to 43; it now writes "$b 1-1", so the first and last part held can be told apart. This applies to any level sitting under one that changes across the range — including the month in "$i 2014-2022 $j 01". Where nothing above a level changes, it is left as it was: "v. 43 no. 6 - v. 43 no. 7" still writes "$a 43 $b 6-7", which loses nothing.
Converter Where only one end of a range gives a value, that value is no longer written as though it belonged to the other end. "v. 1 no. 1 (1995)-v. 12 no. 4 (December 2006)" used to record December as the month the holdings *begin*; the month is now left out, because the statement does not say what it is. The same applies to enumeration: "v. 1 - v. 55 no. 3" leaves the issue out rather than guessing.
Converter When a value has to be left out for that reason, the conversion now says which one — "Only the end of this range gives an issue (3)..." — instead of dropping it in silence. Nothing is written differently because of this; you can simply see what could not be placed, and decide whether to record it by hand.
Converter Two ends naming the same month are kept as a pair rather than merged. "(Jan 1956 - Jan 1957)" now gives "$i 1956-1957 $j 01-01" instead of "$j 01", which read as a single January spanning two years. Where only one end names a month — "(1981 - Sep 1996)" — it is still recorded once, since repeating it would invent a month the statement never gave.
v0.6.1
2026-09-01
Two corrections: a pattern can no longer convert half a statement, and every 863 now says it is compressed.
Workbench A confirmed pattern now has to fit the whole statement before it is used. Until now one could match just part of a statement — the pattern for "v. 9 no. 1 (Nov 1902)" matched the tail end of "v. 1 no. 1 (1995)-v. 12 no. 4 (December 2006)" — and everything before the part it matched was dropped, with nothing on screen to say so. A statement a pattern only partly fits now goes to the standard parser whole, as though no pattern had matched it. Please re-check any file you converted with your own patterns for holdings that begin later than they should.
Workbench The Test button and the example values on the confirmation screen now count a pattern as matching only when it fits the whole statement, so what you see while confirming is what conversion will do. A pattern that fits only part is still shown, along with the part it covers, so you can see how close it came.
Pattern Detector A pattern's match rate now counts only the statements it fits end to end. Some rates that read 100% will read lower — nothing got worse; the number now means what it says.
Converter Every generated 863 now carries second indicator 0, "compressed", instead of 1, "uncompressed". These fields state a range — the first part held and the last part held — which is what compressed means, so each one had been claiming the opposite of what it contained. If your system reads that indicator, records written before this version are worth reloading.
v0.6.0
2026-08-25
A new Holdings Workbench: find a pattern, say what it means, convert with it.
Workbench A new tool joins the other two. It finds the patterns in your holdings the way the Pattern Detector does, then converts with them the way the Converter does — with a step in between where you say what each part of a pattern means. The Converter and the Pattern Detector are unchanged and still at their own addresses; nothing you do today has to change.
Workbench A pattern whose every captured value could be read is confirmed for you as soon as the patterns are found. What is left is the shorter list that genuinely needs you: patterns holding a value the tool cannot place, marked "needs a decision". Removing a confirmed pattern, or clearing the library, is remembered — nothing you have taken out comes back the next time you look for patterns.
Workbench Each pattern is shown against one holdings statement at a time, reading down the screen as the original 866, then the values taken out of it, then the 853 / 863 they produce. Use ‹ and › to step through the other statements the pattern covers; the table and the fields follow. Correct anything wrong and the MARC on screen changes as you do.
Workbench The fields shown for a pattern now carry the linking numbers they would really be given. $8 depends on the whole record — statements published to the same pattern share one 853 and run 1.1, 1.2, and a change of pattern starts 2.1 — so the screen shows the entire record the example belongs to, with that statement marked. It previously showed every statement as 1.1 whatever it would actually receive.
Workbench The original 866 fields are now kept by default. The checkbox that removes them has moved out of Conversion settings to sit above the record list, where you can see it, and starts unticked — so the file you download has both the holdings you started with and the 853 / 863 built from them. Keeping them means the output can be run through the tool again with different settings, and a system that rebuilds 866s from 853 / 863 will replace them anyway. Tick the box if you want them removed as before.
Converter When a serial changes its publication pattern and later changes back, the later run now gets an 853 of its own instead of being filed under the earlier one. A journal running months, then seasons, then months again produces three 853s numbered $8 1, 2 and 3 — the third is a third pattern, not a resumption of the first. Two of those 853s read identically apart from their number, which is correct: they describe separate runs either side of a change.
Converter Holdings that record less detail than their neighbours now share an 853 with them instead of getting one of their own. "v.5(1994)" beside "v.1:no.1(1990)" is the same publication with the issue simply not written down, so both sit under the fuller 853 and the sparser 863 leaves the issue empty. This previously split one publication across two 853s. Holdings that record something *different* — seasons where the others use months — still get their own.
Workbench Where two holdings statements were put under one 853 because one records less detail than the other, the pattern is marked "merged" on the record. Whether they really are one publication is a judgement about the serial rather than about the wording, so if they are not, tick "Keep patterns separate" on that record and each gets its own 853. The choice applies to that record alone and is remembered for the visit.
Converter Because runs are read in the order the 866 fields appear, a record whose holdings are not in publication order may produce more 853s than it should. Check the order of the 866s if a record comes out with more patterns than you expect.
Converter A range written with spaces around its dash — "v. 1 (2001) - v. 5 (2005)" — now keeps its end. It previously read only as far as the first half: an 863 was written for "v. 1 (2001)" alone, and because something had been converted the original 866 was then removed, so the rest of the range was deleted with nothing on screen to say so. The same statement written without the spaces was always read correctly. Please re-check any file converted before this version for holdings that end earlier than they should.
Converter Holdings that begin with a number carrying no caption of its own — "39 no 1 (Spring 1995)" — are now read, with that number taken as the volume. A number sitting a level above an issue is a volume, so "39 no 1" means the same as "v.39 no 1", which already worked. These statements were previously not converted at all.
Converter That reading is applied only where the statement supports it. "2016?" is still an uncertain year rather than volume 2016, and "34 no 3, 4 (Summer, Autumn 1990)" is still left alone: only its first issue can be read, and converting that much would remove the 866 and take the second issue and both seasons with it.
Workbench Where a level is worked out from cataloguing convention rather than stated in the holdings, the value is marked "likely, please confirm" and the pattern is not confirmed for you — it waits for you to look at it, even though the answer is already filled in.
Pattern detector A holdings statement that compresses its range — "v.1-5(1990-1994)", "no.1-6(1990)" — is now read correctly. The hyphen in "v.1-5" joins two volumes; it does not split the statement into a beginning and an end. Reading it as a split put every value after it on the wrong side, so both years in "v.1-5(1990-1994)" were labelled as the end of the range and the "5" was left as a number of no particular kind.
Pattern detector The parts of a generated expression are now named for what they hold — start_vol and end_vol, start_year and end_year — with each level getting at most one beginning and one end. Names such as end_year_2 no longer appear where a plain end_year was meant.
Pattern detector A pattern's heading shows a compressed range as one: "VOL-VOL(YEAR-YEAR)" rather than "VOL#(YEARYEAR)", which ran the two values together and gave no hint that a range was involved.
Workbench Because of those corrections, a statement such as "v.1-5(1990-1994)" now arrives with all four of its values already placed, and can be confirmed without correcting anything first. Statements where a value genuinely cannot be placed — the "5" in "v.1(1990)-5(1994)", which no caption reaches — still ask.
Workbench Holdings that were being left for review can now be converted. "?: 16" has a number in it but nothing to say whether it is a volume or an issue, so it was never converted and never could be. Tell the workbench which it is, once, and every statement of that shape converts.
Workbench Each converted statement says what read it — the name of one of your confirmed patterns, or "Standard parser". Converting a whole file reports the same breakdown, so you can see how much of it your patterns covered.
Workbench The patterns confirmed so far are listed under "Pattern library", folded away to a single line so it does not sit between you and the patterns you are working on. Open it to see what will read your holdings, to remove any that should not be used, or to Export them to a file and Import them again next time — so the work of confirming a collection's patterns is done once rather than every visit.
Workbench The MARC file is uploaded once and used both for finding patterns and for converting. Previously the same file had to be given to two separate tools.
Workbench The screen is one page of three numbered steps rather than a sidebar and a pair of tabs. At the start you see only Holdings; finding patterns appears once you have given it a file or pasted some statements, and converting appears once a file is loaded. Each step shows what the one before it produced, so the work reads top to bottom.
Workbench Each record under Convert says what it will produce before you open it — how many of its statements convert, and how many are held — so a file can be looked over as a list rather than a record at a time. Tick Reviewed as you work through it; the count beside the filters says how far you have got.
Workbench The record list can be narrowed to what you want to look at: only records with something held back, only those a confirmed pattern read, only those the standard parser read, or only those you have not reviewed yet. Open all and Close all work on whatever is showing.
Workbench Long files are read fifty records at a time, with Previous and Next to walk them.
Workbench Records are listed under Convert and open where they sit, showing what that record converts to without leaving the page. The record list previously lived in the sidebar underneath everything else, where on an ordinary screen it fell below the edge of the panel — and since choosing a record was the only way into the conversion view, that view looked permanently empty.
Workbench Holdings matching none of your confirmed patterns are converted exactly as the Converter converts them today, including the ones it holds back for review. Confirming no patterns at all gives output identical to the Converter's, so there is nothing to lose by working here instead.
Workbench That fallback can now be switched off, under Conversion settings. With it off only your own confirmed patterns convert anything, and a statement none of them matches is left exactly as it was, 866 and all. A statement only half covered by a pattern is left alone too rather than half converted — the 866 is removed once anything has been written from it, so converting one range of a two-range statement would take the other with it.
v0.5.2
2026-08-21
Holdings the converter cannot read are no longer deleted.
Converter A holdings statement the converter cannot read now keeps its original 866 field. Previously, converting a record could remove every 866 on it even when nothing was produced to replace them — so a statement in a format the converter did not recognise was deleted outright, and the file you downloaded was missing holdings with nothing on screen to say so. Please re-check any file you converted before this version: look for records that now have no holdings at all.
Converter Converting a single record from its own button follows the same rule. It previously removed every 866 on the record before it had worked anything out, so even statements it had set aside for review were lost.
Converter On a record where some statements convert and others do not, only the converted ones have their 866 removed. The rest stay exactly as they were. Previously the whole record was treated as one decision, so a single statement needing review kept every 866 — leaving the converted holdings recorded twice, once as an 866 and once as an 853/863.
v0.5.1
2026-08-21
Holdings that use slashes between their ranges now produce patterns.
Pattern detector A statement that separates its ranges with slashes — v.1(1990)-v.3(1992) / v.5(1994)-v.8(1997) / v.10(1999)- — is now broken into those separate ranges before patterns are worked out. Previously the whole statement was read as one long run, which was usually reported as too idiosyncratic to express as a pattern, so it produced no pattern at all. Statements separated by commas or semicolons already behaved this way.
Pattern detector Slashes that form part of a number are left alone. Combined issues such as v.1/2, split years such as 1990/91, and month spans such as Jan./Feb. are not split. Only a slash with a space on either side is treated as separating one range from the next.
Pattern detector The Options checkbox now reads "Split multi-range statements on top-level commas, semicolons or slashes". It has always handled semicolons as well as commas; the label mentioned only commas.
v0.5.0
2026-08-04
Corrected how 853s are numbered, and made previews appear on their own.
Converter A single 853 is now shared by every holdings statement that follows the same publication pattern, numbered $8 1.1, 1.2, 1.3 and so on. Previously each statement produced its own 853, so one record could end up with four identical patterns under four different linking numbers. A gap in your holdings no longer starts a new pattern — only an actual change in how the serial is published does.
Converter The 853/863 preview now appears as soon as you select a record. There is no longer a Preview button to press, and the 853 is shown once at the top of each group rather than repeated beside every statement.
Converter Each source 866 is shown side by side with the 863 it produced, so you can check them against each other directly.
Converter Conversion settings moved into their own window, opened with the Conversion settings button. They previously sat in the sidebar, where they overlapped the record list when expanded.
Converter Converting from a record's own button now converts every statement in that record. Doing them one at a time could silently discard the previous one.
Pattern detector Expanding "+ N more" under Example Statements now shows every statement in the group. It previously showed only two, however many the link promised.
Pattern detector Fixed a display fault where pattern cards collapsed to a few pixels and their contents were invisible.
Both The record list and results panel now scroll on their own instead of stretching the whole page.
v0.4.0
2026-08-04
Rebuilt both interfaces for readability.
Both Text is substantially larger throughout. The smallest text on screen went from around 8 pixels to 14, and body text to 18.
Both Added an A / A+ / A++ control in the top corner that enlarges everything, and a light/dark theme switch. Both remember your choice on the next visit.
Both The tools now respect whatever text size you have set in your own browser instead of overriding it. If you had already made text larger, these tools were previously shrinking it back down.
Both Colours were adjusted so labels and borders meet accessibility contrast guidance, buttons and boxes are large enough to click comfortably, and the layout reflows rather than clipping when text is enlarged.
MARC Holdings Workbench No license is granted pending a review of institutional intellectual property rights, and attribution to the original author was made complete.
v0.3.0
2026-08-03
The converter learned a second holdings format and stopped guessing.
Converter Year-first holdings such as "1993: (1 [Feb])" and "2019: (1-6 [Feb-Nov])2020: (7-12 [Jan-Dec])" are now understood. On one test file the share of statements the converter could read went from 6% to 94%; previously almost none of that format could be converted at all.
Converter When a record already has an 853 that describes its holdings, the converter now adds 863s under it rather than creating a second, competing 853.
Converter Statements where it cannot tell what a number means — whether it is a volume or an issue — are held for review and left unconverted, rather than being guessed at. They are listed with the reason.
Converter Running a conversion twice on the same file no longer duplicates fields.
Converter You can now choose which subfields the captions use, and whether chronology is written as MARC codes (03) or as text (Mar).
v0.2.0
2026-07-30
Pattern detector made usable on messy holdings.
Pattern detector Groups too irregular to express as a single pattern are now reported as a finding — "too idiosyncratic to express as a pattern, N statements affected" — instead of producing an unusable expression or an error about length.
Pattern detector Free text inside a holdings statement, such as "Library has:" or "[lacks v.3]", is now handled as a single unit. Generated expressions are shorter and match related statements rather than only the exact one they came from.
Pattern detector Fixed a fault where any group containing free text reported 0% matched, because the generated expression could not match the statement it was built from.
v0.1.0
2026-07-24
First working version.
Converter Converts 866 textual holdings into 853/863 fields, from pasted text or an uploaded MARC file, with month and season written as MARC chronology codes.
Pattern detector Groups 866 statements by structure and generates a named-group regular expression for each pattern found.
Done