Every milestone ends with the corpus regression green, an accessibility pass on the application itself, and an entry here — including what is still missing.
1.4.0 — Getting-started emails you ask for, and the count the privacy page promised
Getting-started emails, only if you ask
Under the sign-in form there is now a box to tick for a few getting-started emails, in English. It starts unticked: creating an account still adds you to nothing.
What you get: a welcome, then at most eight more over your first month — after the welcome, never more than one every two days. Tips, a look at the repair, and a question or two about how it went, answered with one click or by replying. Replies reach a person.
Each email fits what you have done, so while you get them your account keeps a count of how many checks, repair previews and repairs it has run, and when — never a file or its name.
One click in any of them, or the switch on your account page, stops them. Deleting your account deletes the count and your answers with it.
The privacy page says all of this, in all ten languages.
The count the privacy page promised
The privacy page has always said that a check without an account leaves “an aggregate count that a check ran”. Nothing kept one. There is now a daily count of checks, repair previews and repairs — a day, a kind, whether the person was signed in, and the number of pages — and nothing about a person or a file.
1.3.0 — Arabic repaired into letters, every line of a paragraph kept, and a statement for this site
Arabic, repaired into letters
Some producers store each Arabic letter already shaped for its place in the word — ﻛ, U+FEDB, rather than ك, U+0643 — from Unicode’s Presentation Forms blocks, and stretch lines with tatweel. Such a file renders correctly and cannot be searched.
The right-to-left repair now writes letters. The text it puts in /ActualText is folded from presentation forms back to the letters they shape, and tatweel is removed. The folding happens after the reversal: the lam-alef ligature ﻻ is two letters, ل then ا, and folded first it reverses into ال — “the” where the document says “no”.
The detection reads shaped text too. Its word-shape evidence — ة and ى only end a word, ال opens one — looked for letters and found shaped forms, so a line written entirely in them scored nothing. Each form is now read as its letter.
A file repaired before this release still counts as repaired; the check folds both sides before it compares.
Not yet: a file stored in logical order but in presentation forms needs no reordering, so nothing is written for it.
Every line of a multi-line paragraph kept
When one marked-content sequence held two reversed lines, the repair gave its element the first line’s text and treated the second as done. /ActualText stands for the whole sequence, so the second line went silent: a screen reader that used to read it backwards read nothing. The element now carries every line its sequence covers, in reading order.
This site’s own accessibility
An accessibility statement in all ten languages. Every claim in it is a test that was run: axe-core on every page in both colour schemes, reflow at 320 pixels, 150% text with WCAG 1.4.12 spacing on a phone, and the keyboard in three browser engines. It says what has not been tested, too.
An accessibility menu on every page — text size, spacing, high contrast, underlined links, stopped animation, a large cursor — written for this site rather than installed, and claiming nothing.
Six pages scrolled sideways at 320 pixels, each on one unbreakable string, including the headings of the German and Dutch terms. Fixed.
1.2.0 — Batch processing, and the claims trimmed to what ships
· milestone M7
Batch and folder processing
taggart check and taggart fix now take several paths, or a directory, with -r to descend into it.
With more than one input every artefact path becomes a directory: -o, --report-json and --report-pdf each write one file per input, named from the source. Two inputs called report.pdf in different folders produce report.pdf and report-2.pdf rather than one overwriting the other.
A file that fails does not end the run. A backlog is the situation batch exists for, and a backlog always contains something corrupt. Each failure is reported on its own line and the remaining files are still processed; the worst exit code across the batch is what you get back.
The appearance gate runs per file, and a file whose rendering changed is called out rather than buried — it is the one result that must not ship quietly.
Extension matching is case-folded, because a backlog assembled from Windows machines is full of .PDF.
The command line is internal. It is how Taggart’s engine is run and tested here, and it is not distributed: there is nothing to download and no plan that includes it, so the commands above are a record of the engine rather than something you can run. In the app, several files dropped at once are checked into one table, and repairs run one document at a time. (Note added 10 October 2026.)
Claims trimmed to what ships
Custom report branding and shared check profiles were listed as current features. Neither is built. Both now use the line the Team plan was already using honestly for SSO: on the roadmap, not shipped.
Alt-text generation was described in both privacy policies, on the download page, in the home FAQ, in a guide and on a reference page as a shipped feature with three privacy modes including a bundled local model. None of it exists — figure-alt-text refuses to write a value it was not given, which is the correct behaviour and a better privacy story than the one being claimed. A privacy policy is the worst place to describe the data handling of a feature that is not there.
Fixed
The subscription webhook returned 500 on every event. stripe-python returns typed resources whose .get() raises rather than behaving like a mapping, so a customer could have paid and had no subscription recorded. Found by firing real events at the deployed endpoint.
The Stripe setup script duplicated products when run twice in quick succession: it looked them up through the search index, which is eventually consistent.
APP_URL pointed at a hostname that does not resolve. It builds Stripe’s success_url and return_url, so a paying customer would have been redirected nowhere.
1.1.0 — Reference library, and two build gates
· milestone M6
A content release, plus the accessibility work the site and application owed their own subject.
Reference and guides
Five right-to-left failure conditions now have written pages, completing the TG-RTL set: text stored in visual order, missing per-run language, mixed-direction runs, left-to-right column order in a right-to-left document, and misplaced punctuation.
Twenty-seven guides. New this release: checking a PDF free, Word, PowerPoint, Google Docs, LaTeX, scanned documents, Arabic, headings and bookmarks, links and annotations, artifacts and decorative content, titles and metadata, form field naming, colour contrast, tagging an untagged PDF, choosing a screen reader, reviewing remediation someone else delivered, what a remediation deliverable should contain, a checklist that marks each item machine-checkable or human judgement, and PDFs on a website.
Two more Hebrew pages, written rather than translated: checking a PDF free, and producing an accessible PDF from Word. A Hebrew privacy policy naming חוק הגנת הפרטיות and the EU transfer position.
The remediation panel says what it can and cannot do
The Fix panel listed every non-mechanical fix as a checkbox, including thirteen the engine refuses without a per-element approval — ticking one produced an error rather than a fix.
Three groups now. Mechanical fixes in one batch with one undo. Fixes a checkbox genuinely settles, each with a hint written for that fix. And the rest, listed with the reason they are a judgement per element, and a route into the guided review queue. Font embedding says plainly that Taggart will not substitute a font program, because doing so would change the rendered page.
The conformance claim moved to its own card. It had been inside the decisions card, so a document whose only fixes were mechanical could never write the identifier.
Accessibility of the tools themselves
The application had role="tabpanel" on its <main>, which replaced the main landmark rather than adding to it — so the application had no main landmark and all of its content sat outside every landmark. It had no h1. The rendered-page viewport scrolled and could not take focus, which fails 2.1.1. One panel heading skipped a level, which is the condition the application itself reports as 14-003.
Seven tabs, zero axe violations. On the site, 104 pages, zero.
Two gates that run after every site build
Most of this site is generated from the rule file, but only conditions a human has verified get a page — so cross-references to the rest were linking to pages that did not exist. Ninety of them.
check-links.mjs resolves every internal link against what the build actually produced, including the absolute self-references in canonical, hreflang and og:image — which is how a missing social image turned up. A rehype plugin degrades a link to an unwritten condition into plain text, so the prose stays as written and every link turns itself back on the day its page ships.
check-contrast.mjs fails the build if any syntax-highlight colour drops below 4.5:1 against its background. The theme in use paints one token at 3.49:1 on white.
Still the same
167 engine tests, appearance gate at 1.000000 across the corpus, and no claim anywhere that a document is legally compliant.
1.0.0 — First release: check engine, remediation and the RTL engine
· milestone M1–M5
The first public release. Everything below is shipping, not planned.
Check engine
The full Matterhorn Protocol 1.1 rule set — 31 checkpoints, every failure condition — mapped to PDF/UA-1 clauses and WCAG 2.1 AA success criteria in a single shared rule file that drives the engine, the reports and this website.
Every machine-checkable condition the object model can decide, plus heuristics for the human-judgement conditions where a signal genuinely exists.
Three validation profiles: PDF/UA-1, WCAG 2.1 Level AA and IS 5568.
Severity model: blocker for machine-checkable failures, warning where a heuristic says a human will reject it, manual for genuine judgement calls. Nothing is ever auto-passed.
Right-to-left engine
Visual-order detection for Hebrew and Arabic, by comparing the order glyphs are painted in against their positions on the page, corroborated by Hebrew final-letter morphology.
Logical-order repair through /ActualText, leaving the content stream untouched.
Per-run /Lang tagging, in both directions — Hebrew runs in an English document and English runs in a Hebrew one.
Right-to-left aware column and reading-order evaluation.
Remediation
Mechanical fixes applied in bulk with a diff and a single undo.
Semantic fixes — headings, lists, alt text, artifacting — proposed and held for approval rather than applied unattended.
Appearance gate: every remediated file is re-rendered against the original and compared page by page at structural similarity ≥ 0.999. A file that fails is discarded rather than returned. It measures 1.000000 across the test corpus.
Taggart refuses to write a PDF/UA conformance claim its own re-validation cannot confirm.
Reading-order editor
Numbered badges drawn on the rendered page from the real structure tree.
Selection linked between the tree and the page in both directions.
Alt plus arrow keys to reorder from the keyboard, with an undo stack that spans a batch.
A real ARIA tree with roving tabindex, because shipping an inaccessible accessibility tool would be indefensible.
Reports
Remediation report in PDF and JSON: findings, fixes, accepted items with justifications, remaining issues, every human decision with an actor and a timestamp, the tool version, and the SHA-256 of both files.
The PDF report is itself tagged, titled, language-tagged and sets DisplayDocTitle.
Known limits
No batch or folder processing and no command line. Taggart handles one document at a time. This is not a tier you can buy; it does not exist yet.
Font-program internals (conditions 31-011 to 31-026) are reported from the object model; the checks that require parsing the embedded font binary are marked partial in the rule file and say so in the report.
No OCR. Taggart detects that a document needs it and points at ocrmypdf rather than building a worse one.