Removing pronunciation guides sounds like a small editorial task, but the safe acceptance condition has two parts. The EPUB must contain no ruby markup, and the characters that the ruby annotated must still be present. A search that proves only the first condition can hide the worst possible failure: deleting both the reading and the word itself.
This walkthrough uses a deliberately tiny pair of EPUBs so that every claim can be traced to a stored file. The before package contains one ruby element around the base text “漢字.” The separately generated after package contains zero ruby elements while “漢字” remains in its XHTML. The test isolates structural removal from visual rendering and also records a leftover source marker that should not be mistaken for a clean production manuscript.
Removal Has Two Independent Acceptance Tests
Treat ruby markup and base text as separate inventory items. For the before package, the structural count is one <ruby> element. For the after package, that count is zero. Independently, a text extraction from the after XHTML must still find the two base characters “漢字.” Both checks are necessary: ruby = 0 establishes that the annotation structure is gone, while the surviving text establishes that the edit did not erase the word.
The stored before EPUB has SHA-256 e22b7691ae0d45ec83c8c968f423c6adc11efd6794cc3e34e9f29972f3962555. The stored after EPUB has SHA-256 41f488f613a61316d4dd5017889ff9ea424aa8f7170c5ea7f45b360161df4aeb. Different paths and different hashes make the comparison reproducible; it is not an inspection of one overwritten file.
Build a One-Pair Before File
The controlled before source contains a single annotated term rather than a chapter full of unrelated typography. Rune generated an EPUB from that source, and the package was then reopened as a ZIP archive. Its manifest entries all resolved, so the file was not merely present on disk: its internal resources could be inspected. Searching the content XHTML found exactly one ruby element and the expected base text.
This small fixture is useful because its expected answer is known before the export. If the ruby count were zero at this stage, the setup would be invalid and no after comparison should proceed. If the count were greater than one, the input would contain an unintended second test case. Establishing the baseline prevents a later “successful” zero from being credited to a source that never contained ruby in the first place.
Make a Separately Named After File
For the after fixture, the annotated source was replaced with a controlled line that retains the base word but omits the ruby pair. Rune generated a second EPUB at a separate path. Keeping both outputs is more than bookkeeping: it allows another operator to recompute the counts, compare package contents, and verify that the after result was not produced by silently overwriting the baseline.
The after archive reopened successfully, all referenced internal files were present, and the XHTML ruby count was zero. The literal base text “漢字” was still found. Those are the measured results behind the procedure to remove ruby from EPUB content safely. They do not prove that every reader will display the page identically; they prove the package-level transformation represented by these two fixtures.
Inspect the XHTML, Not Just the Source Line
A source preview is not enough for release acceptance. Rune may normalize text while generating the package, and a reader may apply its own layout rules afterward. The durable inspection point is the generated XHTML inside the EPUB. Open the archive, locate the content document referenced by the package manifest, count <ruby> nodes, and search the resulting text for each required base expression.
For this fixture the expected table is simple: before equals one ruby node; after equals zero; after base-text presence equals true. The package integrity check must also report no missing manifest resources. A screenshot would add visual context, but it would not replace these structural checks because a screenshot cannot prove that hidden markup is absent throughout the document.
Recover When the Base Characters Disappear
The dangerous failure state is ruby = 0 combined with no match for “漢字.” That means the operation removed too much. Do not patch the generated XHTML as the primary recovery, because a later regeneration would discard the manual repair. Return to the source, restore the base characters without the reading, generate a newly named candidate, and repeat both inspections.
Another failure is a package that cannot be reopened or contains a manifest reference to a missing file. In that case, the ruby result is not trustworthy because the inspected archive is incomplete. Regenerate from the last known source, retain the failed output for diagnosis, and accept only a new package that passes integrity, ruby-count, and base-text checks together.
What the Remaining Vertical Bar Means
The after fixture contains the extracted line |漢字の合成原稿です。 The vertical bar remains even though the ruby element count is zero. This is an important boundary in the evidence. The fixture proves removal of the ruby structure and preservation of the base characters; it does not prove that all authoring notation has been cleaned from the prose.
In a production manuscript, decide whether that bar is meaningful punctuation or a ruby-source marker. If it is only a marker, remove it in the source and generate a third, separately named candidate. Then verify both the zero ruby count and the intended plain text again. Reporting the bar openly keeps the structural claim precise and prevents a technically valid test package from being mistaken for publication-ready copy.
Scale Up With a Ruby Inventory
For a full book, record the expected ruby count before editing and list the base expressions that must survive. A global count of zero is valuable, but representative words from every affected chapter make the preservation check stronger. When identical terms appear many times, include a chapter path or nearby phrase so that the test identifies the intended occurrence rather than an unrelated duplicate.
Process chapters in small batches. After each batch, generate a candidate, inspect its content XHTML, and compare the results with the inventory. This narrows the cause if a base term disappears. It also separates editorial choices—such as keeping ruby for a rare name—from mechanical removal. The evidence pair in this walkthrough remains deliberately minimal; scaling it means adding traceable cases, not relaxing the two-part acceptance rule.
A Release Checklist for Ruby Removal
Before release, retain the before and after sources, the two EPUB paths, and their SHA-256 values. Confirm that both archives reopen, every manifest reference resolves, the before ruby count matches the known baseline, and the after count is zero. Search the after XHTML for the required base characters and review any surviving source markers such as the vertical bar.
Finally, open the candidate in the actual reading applications used by the project and inspect the affected paragraphs. That reader-side rendering step was not performed for this controlled evidence set, so no claim is made about a particular app’s visual result. The package checks establish a reliable handoff point: ruby changed from one to zero, “漢字” survived, and the remaining cleanup question is explicitly identified rather than hidden.