Releases: clintecker/press
Release list
press v2.3.1
A hardening release. Two output bugs are corrected -- a retail barcode that
crowded its quiet zone, and a cover commission that invented generic motifs
when the book named its subject only in prose -- and a latent hole in the
adapters boundary gate is closed, so the "one approved home for a subprocess"
invariant is now enforced by construction rather than held by luck. Three
verifier guards gain the known-bad fixtures that prove them, and the landing
page features Make Ready as the flagship book built end to end through the
press. Compatible within v2; no build changes a valid book's typography or
layout.
Changed
- The landing page features Make Ready as the flagship showcase -- a book
taken end to end through the built-in facilities: a commissioned clothbound
cover and fourteen engraved plates finished bypress art enhance, the
reader dressed in the book's own cloth, a subject index, registered ISBNs,
and a table of authorities. It stands beside Mostly Done. as proof the
pipeline makes real books, not just demos.
Fixed
- The retail cover barcode no longer crowds its quiet zone (#210). The
EAN-13 symbol was drawn in a TikZ node whose default padding shifted it
left, so the first guard bar read as ink inside the left quiet zone and
verify-printrefused an otherwise-correct wrap. The barcode node now sets
inner sep=0(matching the front-cover-art node), so the symbol sits exactly
where the verifier's pixel model expects it. The integration cover-wrap
fixture now carries a real print ISBN, so the quiet-zone check runs in CI. - A cover commission draws the book's own subject instead of inventing
one. When a book stated its subject only indescription(or as a
cover.emblem) and not as an explicitcover.subject,press coverfell
back to the literal phrase "the book's subject" and the image model invented
generic motifs. It now draws the subject from--subject, then
cover.subject, then the book'sdescription, thencover.emblem, and only
then the literal -- so a book that says what it is about gets that on its
cover. - The adapters boundary gate no longer has a from-import blind spot. The
gate that proves nothing outsidepress.adaptersholds a direct subprocess
or environment call matched only thesubprocess.Popenattribute form;from subprocess import Popenandimport subprocess as spslipped past it, and
the process controller's launcher did exactly that -- a real subprocess the
gate reported as clean. The gate now flags the from-import binding of an
executor and resolves aliased module imports, and the one production launcher
has moved intopress.adapters(its streaming sibling ofSubprocessRunner)
where a boundary call belongs, so the single-home invariant is enforced, not
merely intended. Three verifier guards -- plate-link resolution, cover-wrap
transparency, and barcode readability -- also gained the known-bad fixtures
that give them teeth.
press v2.3.0
The art department grows a finisher, and a book becomes its showcase. The press
learns to finish a commissioned plate -- upscale it through a style-matched
model, quantize it to a small palette, and write it as a lossless PNG smaller
than the JPEG it replaces -- and the whole plate pipeline becomes format-
agnostic so that PNG is a first-class plate. The operator desk shows more of
what it already knows, three confirmed defects are fixed, and the reference
book Make Ready. is re-commissioned end to end through the built-in facilities.
Compatible within v2.
Added
press art enhancefinishes plate art for print and web in three
style-matched stages: an AI upscale through a Real-ESRGAN model chosen for
the medium (a line model for an engraving, not a photo model), a resample to
a print-grade long edge, and a quantize to a small palette written as a
lossless PNG. The medium inconfig/aesthetic.yamldrives the model and the
palette. The upscaler is a detected external tool (Upscayl'supscayl-bin
or a standalonerealesrgan-ncnn-vulkan), reported bypress doctor; absent,
the command still quantizes and compresses, so the win lands without it. This
retires the standing scar that "PNG barely compresses engraving grain": once
the grain is quantized to a handful of grays, a plate ships as a lossless PNG
smaller than the lossy JPEG it replaces.- The operator desk shows more, and shows progress. The dashboard renders the full
press doctorreport -- every tool's state and its purpose -- not just a one-line summary, and a run screen tracks the build's stages as they stream by instead of only echoing the log. The command list was already complete (catalog-driven, parity-enforced); this surfaces the data the desk already held.
Changed
- The plate pipeline accepts PNG as well as JPEG, so a plate finished by
press art enhance(which produces a lossless quantized PNG) is a
first-class plate: it is counted for the List of Plates, verified, and
print-prepared exactly as a JPEG plate is. Every place that resolved plates
globbed*.jpgonly, so an enhanced book silently lost its List of Plates
and its plate verification; they now resolve through onebooklib.plate_files
helper that returns both formats. This completes the enhance feature and
fully retires the "PNG barely compresses engraving grain" scar.
Fixed
- The page secret scan no longer false-rejects a book whose own words
contain "secret" or "password". The credential marker matched bare
English substrings, so a valid book titled "Secrets of the Trade", or any
page whose prose read "the secretary kept the password to herself", failed
press pages/verify-pages/checkwith a spurious "page metadata
leaks private build data or a secret" -- the og:title, og:description, and
JSON-LD carry the book's own title and prose legitimately. The marker now
matches on credential shape (a provider key prefix, a bearer token, a
credential-bearing query parameter, or a key=value assignment whose value
looks like a token), never a bare word, closing the false positive across
all three scans that share it (the metadata head, the rendered-page
commerce scan, and commerce-config validation) without weakening detection
of a real leak such as?apikey=sk_live_.... - An ISSN lookup no longer reads one issued ISSN as a collision. The live
ISSN Portal returns a resource's JSON-LD as the main node plus#ISSN,
#KeyTitle,#Record, ... fragment sub-nodes on the same base IRI; every
node reduces to the same eight digits, sopress lookup issncounted them as
several resources and returned AMBIGUOUS for a perfectly good ISSN. The match
now collapses the nodes of one resource by their fragment-stripped IRI, so
AMBIGUOUS means two genuinely distinct resources carry the ISSN, and the
ordinary success path resolves to FOUND. - The print-profile PDF checks gain the known-bad fixtures they lacked.
verify_black_inkandverify_mirrored_margins-- the black-ink-only and mirrored-gutter guards for a print interior -- had no negative test, so breaking either left the suite green. Each now has a synthetic page it must reject (a colored region; a wrong-side gutter), confirmed by mutation.
press v2.2.1
Mobile and boundary repairs, no design change to any book. The documentation
site's masthead no longer collapses and its wide tables read on a phone; a
book's own web tables stack on a narrow screen while rendering byte-identically
at reading width; and a registration lookup bounds its response as it reads it.
Compatible within v2.
Fixed
-
A registration lookup bounds the response body as it reads it (#209).
The size cap was applied to the body the transport had already read, so a
server that omitted or lied aboutContent-Lengthdecided how much memory
a lookup spent before the cap could refuse it. The bound now travels with
the request:adapters.http.urlopen_transporttakes an optional
max_bytesand reads one byte past it, so an overrun is visible and fails
closed rather than being truncated in silence. It is opt-in and unbounded
by default -- a cover image and a provider payload legitimately read
whatever the server sends, and a blanket cap would silently truncate them. -
Wide tables are readable on a phone, on every HTML surface the press
publishes. A three- or four-column table used to run its far columns off
the edge: on the docs site it scrolled sideways inside its own box, and in a
book it fell back to browser defaults, which styled it not at all. Narrow
screens now stack each row into a card, and every cell wears its column's
header -- carried onto the cell asdata-labelby
webmeta.label_table_cellswhen the page is built, because CSS cannot reach
a cell's header on its own. One implementation serves the docs site, the
book's reader pages, the landing page, and the single-file HTML edition.
On the book surfaces the change is scoped to the narrow breakpoint and
nothing else: at reading width a book's tables render exactly as they always
have (proven pixel-identical), because within a major the press may correct
broken output but must not restyle a valid book. Giving tables a house
treatment at every width is a design change and waits for the next major.
Tables with no header row -- the reference records, a book's downloads
list -- already read in two columns and are deliberately left untouched. -
The masthead lockup no longer collapses on the documentation site. The
desktop sidebar is a column flex container capped at the viewport height, and
the lockup'soverflow:hiddenzeroed its automatic minimum size, so under
shrink pressure the box collapsed to nothing and sheared the logo to a sliver
at every desktop width. The browser layout check now measures the clipping
box against the image -- the image reported its full height throughout -- and
refuses a stacked table that still scrolls sideways or clips a cell.
press v2.2.0
Composability and proof. The typed adapter boundary closes over the whole
package, so a direct process, environment, or tool call is now refused
anywhere outside press.adapters; every public web surface a book publishes
carries one honest metadata contract; the packaged provider ledger becomes a
generated projection of its canonical source; and the two prose checkers a
book runs are held in step by a differential corpus. The repository's own
security baseline is proven end to end, limitations recorded rather than
claimed away. Compatible within v2: no typography or layout changes, and a
book with no site-url publishes byte-identically to before.
Added
-
Opt-in read-only registration lookups (#203).
press lookup lccn <number>andpress lookup issn <number>resolve a record from the
Library of Congress and the ISSN Portal through read-only adapters, off
by default: network access is explicit, response parsing is defensive
(ElementTree expands no external entities), and every failure resolves to
an honest UNAVAILABLE rather than a crash. Withregistrations.lccnor
registrations.issnconfigured, the number argument is optional. -
A jargon-parity contract between the packaged checker and the portable
skill copy (#201, INV-editorial-jargon-parity). A differential corpus
and fuzz prove the press's jargon checker and the standalone skill agree
case for case, and a source-identity check holds their shared logic
byte-identical, so the copy an author runs cannot drift from the one CI
enforces. -
Automatic roadmap reconciliation (#197). The
Roadmap integrity
workflow reconcilesroadmap/milestones.jsonand ROADMAP.md against the
live GitHub milestones after a merge tomain(and weekly), so the
registry cannot silently drift from the issues it tracks. -
One metadata contract across every press-built web surface (#158).
Canonical URLs, Open Graph, Twitter cards, and JSON-LD now cover the docs
site, the book landing page, the reader index, and every chapter page,
generated from the book model rather than duplicated in templates.
src/press/webmeta.pyis the single emitter, so the rule that an offline
or preview build omits everything URL-shaped -- canonical,og:url,
og:image, and the URL fields inside the JSON-LD node -- lives in exactly
one place: a book with nosite-urlships no falsely-canonical output.
The book site also gains asitemap.xmlandrobots.txt, emitted only
when asite-urlis configured.verify_pagesgainscheck_metadataand
check_book_sitemap, with eleven damage fixtures they must reject.
Changed
- The typed adapter boundary is now complete (#199). The last nine
legacy modules --__main__,booklib,scaffold,selftest, and the
verify_*/gen_coverwrapfamily -- route every process, environment,
and tool-probe call through the typed adapters. The boundary gate's legacy
allowlist is deleted, so a directsubprocess/os.environ/
shutil.whichcall is now refused anywhere outsidepress.adapters, and
the import-side-effect sandbox moved toadapters/import_guard.py. Every
migrated site is proven to drive its injected adapter under a recording
fake; deterministic composition, no behavior change. - The packaged provider ledger is now a generated artifact, not a
maintained duplicate (#200).quality/providers.yamlis the one
canonical source;src/press/data/providers.yamlis a deterministic
projection of it (a fixed banner, then the canonical bytes verbatim),
regenerated bypress selftest --write-docs. The selftest and the
distribution tests now compare the packaged copy byte-for-byte against
that projection, so a comment-only or whitespace edit — drift a semantic
compare missed — fails CI, and the wheel can no longer ship a hand-copied,
divergent record. The duplicated header and footer comment in the old
mirror are gone. The update/review workflow is documented in
docs/PROVIDER-DATA.md, linked from the print-format docs.
Fixed
- Collection-policy meta-tests are warning-clean across the supported
pytest and pytest-asyncio range (#202). The nested pytest runs disable
the asyncio plugin and the root suite pins the fixture loop scope, so a
version bump within the supported range no longer raises warnings.
press v2.1.0
The art department and the test bar. The press gains a cover-design system and
an in-book illustration system, its toolchain image goes native on Apple
Silicon, and — after a title-page generator shipped a dropped and a clipped
cover behind green integration tests — every example book is now verified as a
built artifact and the machinery that lets a producer ship unproven is closed.
Compatible within v2: a book without a baked cover renders byte-for-byte
unchanged. The one design change touches only books that carry a cover — the
cover plate now fits the text block of whatever trim it is, correcting a fixed
plate that clipped on 5×8 and overflowed the block even at 6×9.
Added
- A cover-design system (
press cover). Ten house cover styles in a
catalogue (src/press/data/cover-styles.yaml), selected by
config(cover.style,cover.subject) and rendered through the shared
image-model layer; a book may also write its own style directly into its
repo. The art is generated once and committed as a static asset, never in
CI, so a build is deterministic. Listed bypress coverand documented on
the site with visual examples. - An in-book illustration system (
press illustrate). Seven single-ink
illustration media (src/press/data/illustration-styles.yaml) for plates,
maps, and diagrams, selected byplates.style;--fromturns real source
material (a photograph the author took, a rough map) into a house-format
plate. Installed throughpress art accept --as plate:<name>, so it lands in
the same geometry-checked pipeline as every other commission. - A gallery of eight example books, each with a distinct palette, a real
Penguin-style illustrated cover, and its actual built PDF with page previews
on the site — the press proving, on itself, that nothing is hardcoded. - The example PDFs are verified in CI. The gallery build now runs
press verifyon every example it builds; a book whose PDF loses a sentinel,
a cover, or a page turns the build red. This caught a fragile sentinel on its
first run. - A producer must name the rejection its verifier turns on. Every module
classifiedproducerin the surface inventory is now held, by the selftest,
to an entry inPRODUCER_REJECTION_PROOFS(or a visible, shrinking pending
list) — so a new artifact-maker cannot inherit a blind verifier the way the
title-page generator did. - A coverage-floor gate. A module baselined below 50% branch coverage must
now name its reason in the ratchet's allowlist, and the list may only shrink;
a new, silent low floor turns the gate red. CONTRIBUTING gains a "what a proof
has to prove" section stating the principle: assert the artifact, not that the
line ran.
Changed
- The toolchain image is multi-arch (#206).
press-toolchainis now built
and smoked on native runners for bothlinux/amd64(CI) andlinux/arm64
(Apple Silicon), assembled into a manifest list; local Docker PDF builds on a
Mac run natively instead of dying under qemu.build.ymlpins the multi-arch
image, so a book's CI resolves the exact multi-arch bytes. - A baked cover fits the text block of any trim. The generated title page
sized its cover plate to a fixed 5.6×7.1in box; it now fits\textwidthby
\textheight. A book carrying a cover renders its cover page at the trim's
own proportions (on 6×9, a hair smaller and no longer overflowing the block);
a book without a cover is unaffected.
Fixed
- Every book's reading PDF leads with its cover, on any trim. The cover
plate rendered only when a book suppliedconfig/front-matter.yaml, so a book
with acover.jpgand no front-matter config shipped with no cover at all;
and where it did render, the fixed plate size clipped on 5×8. Covers now
trigger on the asset itself and fit the trim, andverify_pdfrefuses a
reading PDF whose first page is not the cover — the miss that started this
release, now a checked property. - The producer gate runs from an installed wheel. It read the repo-only
surface inventory unconditionally and crashedpress selfteston a fresh
install; it now skips outside a checkout, like the other repo-reading checks. - A gallery example's sentinel moved off its drop cap. A sentinel anchored
on a chapter's opening word could never match, because the house drop cap
raises the initial and small-caps the remainder; re-anchored mid-chapter. - Site reference tables render correctly on desktop, drop caps stay off back
matter, the gallery preview strip no longer scrolls, and the
signal-and-noise example's index-terms schema builds.
press v2.0.0
The composable press. A new design major: trim, binding, cover material, and
print vendor are configurable; typography and web design are profile-driven;
chapters may open with a drop cap; and books extend the press by declaration.
A @v1 book is unaffected and keeps rendering byte-for-byte; a book opts into
v2 by repinning (press migrate), and until it selects a non-house profile,
even a @v2 build is unchanged.
Fixed
- The cover wrap is now print-safe (#189). The wrap embedded the raw
assets/cover.jpgand imprint logo, so a transparent logo (a soft mask) or
an over-resolution source reached the cover and tripped a print-on-demand
preflight (Lulu, KDP), even though the interior had been cleared. The
generator now embeds flattened, resolution-capped copies via
print_safe.prepare_cover: the logo is composited onto the exact field
colour it lies on (so it stays invisible against the field, with no soft
mask), and both cover art and logo are capped from the wrap geometry, since
the logo prints small on the cover (a 1000px logo at 1.1in is 909 PPI, over
the limit) where the same file clears the interior's roomier placement.
verify_coverwrapnow refuses a wrap that carries transparency or an image
over 600 PPI, so a regression cannot ship a cover a printer would reject.
Verified end to end on a real 46-page 6×9 wrap: the logo drops from 1024²
RGBA at 909 PPI to an opaque 649² at 590 PPI, with zero soft masks.
Added (v2)
- Semantic chapter-opening drop caps (#192). A design may open each
chapter with a dropped or raised initial, and the manuscript stays ordinary
prose: no\lettrine, no CSS floats, no font commands. The decision is made
at the document-tree layer by a pandoc Lua filter that finds the first
eligible paragraph after each chapter heading (skipping an epigraph or other
non-prose opener) and splits its opening word into a Unicode grapheme
initial (a base letter with its combining marks, never a stranded accent),
the leading punctuation kept with it, and the remainder of the first word.
For the PDF it emits a single centralized\PressDropCapmacro (built on
lettrine, with aneedspaceguard so a chapter opening is never stranded
at the foot of a page); for HTML and EPUB it emits semantic
chapter-opening/drop-capspans a floated stylesheet renders, with a
clearfix so a short opening paragraph never overlaps the initial. Enabled
through the profile (design default) or a book's ownchapter-opening
override (style,lines,small-caps-remainder); off by default, so a
book that does not opt in renders byte-for-byte unchanged (proven by the
house visual baseline showing zero drift with the filter installed). The
literary-novella gallery example opts in to show it. Guaranteed by
INV-dropcap-opening, proven at the grapheme level intest_dropcapsand
at the emission level by running the filter through pandoc. - A gallery of very different example books (#190), proving nothing is
hardcoded. Five complete books underexamples/— a naturalist field guide,
a poetry chapbook, an academic monograph, a literary novella, and a seasonal
cookbook — each produced by the same pipeline with only its own config
differing: two trims (house 6×9 and novella 5×8), five aesthetics, footnotes,
a subject index, a custom web stylesheet, four kinds of front matter, three
kinds of appended matter, and a per-book jargon allowance. Every example is
proven a valid press book on each test run (the config passes the typed
model, the design surfaces genuinely vary, and each passespress check),
and the docs site gains a gallery page cross-linked from the parts-of-a-book
and configuration guides. - Registrations automation: ONIX 3.0, PCN prep, and ISBN conversions
(#191).press onixgenerates the ONIX 3.0 metadata record distributors
ingest (dist/<slug>.onix.xml) from config: a product per sellable edition
(the print ISBN as a physical product whose form follows the binding, the
EPUB ISBN as anEAproduct), the ISBN asProductIDType15, title,
contributors, publisher, and a year-only publishing date — degrading
honestly where the press holds nothing (no<Price>, because a book
repository holds no price by design).press pcnassembles the Library of
Congress PrePub Book Link field values (dist/<slug>-pcn.txt) for the LCCN
application, flagging any gap the form needs. Newregistrationshelpers
round out the arithmetic: ISBN-10↔13 conversion and the ISBN-10 / ISSN
mod-11 check digits. There is no API that issues an identifier or accepts a
feed without human onboarding; the automation is the generate/validate/
format side, and the manual gates are documented honestly. - Typography and web design are now profile-driven (#172): a design
profile carries not just trim and margins but the structural type treatment
(paragraph indent, leading) and the web reading measure (max width, base
size, line height). The house profile projects exactly the v1 values, so a
house book renders byte-for-byte unchanged — proven against the committed
visual baseline with zero drift — whilenovella-5x8becomes a genuinely
different qualified design (its own type treatment and measure, not just a
resized house). The split is deliberate: the profile seals the structural
typography that defines a design, and the aesthetic keeps owning identity
(font family, palette), overriding the profile. Each profile has a stable
digestover its design-affecting data, so a sealed value cannot change
without the key that scopes its visual baseline moving; a new
INV-profile-geometryproves every profile renders at its declared trim. - The v1→v2 migration and rollback contract (#174):
press migrate
moves a book to the next press major by repinning it — the press major in
requirements.txtand the CI workflow — and nothing else. The
manuscript, config, and accepted art come out byte-for-byte identical; a
dry run (press migrate plan) reports every change and design consequence
before any mutation;applywrites an exact backup first;rollback
restores the pre-migration bytes exactly. Because the house profile
reproduces the sealed v1 geometry, a v1 book that repins to v2 and keeps
the house profile renders unchanged — the design moves only when the
author selects a non-house profile. Custom overrides the profile does not
govern (tex/title-page.tex,assets/web/*.css,config/aesthetic.yaml)
are named by the plan, never silently carried. Guaranteed by
INV-migration-safeandINV-migration-preview, proven by
check_migration's scaffolded-book round-trip, and documented in
docs/MIGRATION.md. - The extension contract (#171): the decision record and executable gate
for what a book or third party may add to the press. Everything extensible —
a design profile, provider spec, artifact, skill, or workflow — is a named
data file selected by id, never an imported plugin, so behavior cannot come
from import or entry-point order. An extension carries a manifest declaring
the names it claims, the contract major it targets, the invariants it takes
on and their proofs, and its capabilities;press'sconformancegate
refuses a manifest that collides with a core name, targets an unsupported
contract major, is malformed, names an unknown dependency, claims a sealed
capability, or leaves an invariant unproven — before anything is built. The
mandatory verification, path containment, artifact graph, config validation,
and release gate stay sealed. Modelled byINV-extension-conformanceand
INV-extension-seal, proven bycheck_extension_conformanceover a
reference and five hostile fixtures, and documented in
docs/EXTENSION-CONTRACT.md.
Changed (v2 — breaking, configurable print formats)
- Trim, binding, cover material, and print vendor are now configurable, a v2
(design-major) change: a book pins@v2to opt in, and a@v1book stays
a 6×9 paperback, byte-for-byte. Design is modelled as versioned print
profiles (print.profile) carrying trim and interior geometry; the house
6×9 profile reproduces the v1 output exactly.print.binding
(perfect-bound, saddle-stitch, coil, casewrap, dust-jacket),print.material
(paperback, casewrap, linen), andprint.providerselect the rest. Trim is
derived from the profile, not hand-entered; theINV-config-triminvariant
is rewritten around it. - Provider manufacturing specs for Lulu, KDP, and IngramSpark (from
sourced, attributed research): the spine caliper, cover bleed, safety, and
hardcover wrap geometry are vendor-specific and no longer hardcoded. The
spine model branches on binding (a paperback formula vs a hardcover lookup
or caliper), and the cover generator composes per-binding geometry that
matches IngramSpark's published casewrap and jacket formulas. Unsupported
combinations (a dust jacket at KDP, an uncut trim, a page count out of
range) are refused before rendering. - A user guide,
trim & binding,
and the internal design recorddocs/PRINT-PROFILES-PLAN.md.
press v1.20.0
Brand identity: the press pilcrow mark and lockup across the CLI (a banner,
status glyphs, and the house palette), the docs site (favicon, nav lockup,
social card), and the README.
Added
- Brand identity: the pilcrow mark and the
press.lockup. The docs site gains
a favicon, a theme-swapped nav mark (ink badge on light, vermilion on dark),
and a large social card (og:image/twitter:image); the README shows the
theme-aware lockup. Assets live insite/brand/. - CLI branding (
press.brand): a runningpresswith no command shows the
block banner and tagline, andpress allends with a "your book is ready"
line, in the house vermilion. Color is emitted only to a real terminal
(honoringNO_COLOR/FORCE_COLOR), so piped output stays plain and
scriptable.
press v1.19.1
Print pack, registrations, and public-readiness: offline ISBN assignment from
an owned prefix, print-safe interior images that clear the Lulu file warnings,
a top-to-bottom Lulu printing guide and a parts-of-a-book guide, versioned
dependency/code/secret security controls, Python 3.14 support, and a
repository-metadata drift check.
Added
- Offline ISBN assignment (
press isbn): record the registrant prefix your
agency sold you asregistrations.isbn-block: {prefix, size}, and
press isbn assign print|epubmints the next unused ISBN-13 from it —
computing the check digit, hyphenating with the agency's own prefix
hyphenation, and writing it toregistrations.isbn.press isbn status
shows what is used and free; a malformed block failspress check, and an
exhausted block or an already-assigned edition is refused. There is no API
that issues an ISBN — you buy a prefix once, then assign from it offline.
Also addsregistrations.lccn_normalize(the Library of Congress canonical
LCCN form). - Python 3.14 is a supported and tested version. The suite and the desk pass
on 3.14; CI's package matrix runs it on Ubuntu alongside 3.10-3.13, the
wheel declares the per-minor classifiers,press doctortreats 3.14 as
in-range, and the installation and compatibility docs name the 3.10-3.14
range (#168). - A scheduled
Repository metadataworkflow asserts the repository's
discovery configuration cannot silently drift: the homepage points at the
docs site, the default branch ismain, wiki and projects stay disabled,
and the topics remain set. It runs weekly and on demand, read-only (#165). - Print-safe interior images (
press.print_safe): theprinttarget now
flattens transparency onto white and caps image resolution, so a
print-on-demand vendor sees no transparency and no image over 600 PPI. A
pandoc Lua filter redirects manuscript figures to the sanitized copies under
build/print-assets/, and the generated front matter's logo follows; the
reading PDF is unchanged. On the reference book this cleared both Lulu file
warnings and roughly halved the interior PDF. A book with a hand-authored
title page points its own logo atbuild/print-assets/to match. - A top-to-bottom Lulu printing guide:
which two files to upload, why the cover wrap fits Paperback Perfect Bound
(and not the hardcover/dust-jacket templates), the Lulu settings that must
match a book's config, the two advisory file warnings press produces (the
transparent logomark and its ~602 PPI placement) with their fixes, and a
troubleshooting table. - A task-oriented guide, the parts of a book, covering
how to add each common part: the byline, the generated front matter
(dedication, epigraph, acknowledgements, colophon), the author portrait, an
about-the-author page, further-reading and glossary pages, footnotes, the
index, and the sources-and-authorities bibliography. It leads with the
press configcommands and is honest about which parts are authored
Markdown rather than configuration. - Versioned security controls (#154): a Dependabot config covering the
Python package, the pinned GitHub Actions, and the toolchain base image
(weekly, grouped); a CodeQL workflow analyzing the Python package on every
pull request, push to main, and weekly; and a dependency-review workflow
that fails a pull request adding a high-severity vulnerable dependency.
Each new workflow runs at least privilege and uploads nothing to a third
party.
press v1.18.0
Book web surfaces and developer-experience: structured metadata on the book
landing page, a real start-reading reader index, git-index isolation so the
commit hook runs without a workaround, and documentation corrected against
the current code.
Added
- The book's landing page declares structured metadata generated from the
book's own config (#158, book half): Open Graph and Twitter-card tags, and
a schema.orgBookJSON-LD node (name, authors, publisher, description,
date, and the available editions asworkExample). Nothing is invented --
a canonical URL,og:url, and cover image appear only when asite-url
(and cover) is configured, so an offline build never claims a false
canonical.press verifyfails if the landing metadata drifts from the
config: a stale JSON-LD title, a canonical without a site-url, or a
site-url without a canonical.
Fixed
- The chunked reader's index is a start-reading page, not an empty shell. Its
<main id="content">-- the target of the "Skip to chapter" link -- was
empty, so the skip link went nowhere and there was no explicit way to begin
reading. It now opens with an orienting line and one primary "Start
reading" action pointing at the first part (by the same ordered manifest
the previous/next pager uses), above the chapter contents; a chapter page
keeps its own body inmainand gets no start-reading block (#160). - Git subprocesses observe only their own repository. A
git commitruns
its hooks withGIT_INDEX_FILE(andGIT_DIR) pointing at the outer
commit's transient index, so the test suite -- and press itself -- would
build or inspect a nested repository against the wrong index (a source
archive came out empty, damage tests failed for the wrong reason). The
production process runner now strips the ambient repo-bindingGIT_*from
every git command it runs, closing the leak at the one boundary all git
calls pass through; an explicitly injected git env is still respected for
tests where git is the subject. The full suite now passes inside a real
git commithook without a workaround (#176).
press v1.17.0
A public-experience and maintenance pass: accessibility landmarks and
declared metadata on every docs page, community scaffolding and governance,
one contributor verify command, every Action off the deprecated Node 20
runtime, and the code deprecation warnings cleared.
Added
- Public-project scaffolding: structured GitHub issue forms (defect,
proposal, documentation) that ask for the diagnostics a report needs and
route security privately, a pull-request template tied to the project's
actual contracts (#163); a Contributor Covenant Code of Conduct and an
honest single-maintainerGOVERNANCE.mdcovering decision/release/security
authority and bus-factor (#164); andscripts/verify.sh, one fast-to-
complete command that runs the local half of CI's quality gate
(lint/type/selftest/pytest, then the coverage and mutation ratchets and
the site build), documented in CONTRIBUTING (#162). The repository's
discovery metadata (homepage, topics) and auxiliary-surface flags are set
(#165). - The documentation site declares its metadata instead of leaving search
engines and link previews to infer it: every page carries a canonical URL,
a meta description derived from its own first paragraph, and Open
Graph/Twitter-card tags, and the build emits a deterministicsitemap.xml
androbots.txt. The build fails if a page lacks a canonical URL or
description (part of #158; book-page structured data is separate). - Every documentation-site page declares its language (
<html lang="en">),
exposes onemainlandmark, and leads with a skip-to-content link as the
first focusable element; the build fails if a page lacks any of them
(#157). The CSS-only mobile menu shows a focus ring on its toggle so it is
operable and visible by keyboard (#156). (Internal doc links already stay
on the site rather than bouncing to GitHub, #159.)
Changed
- Every pinned GitHub Action moved off the deprecated Node 20 runtime to its
current Node 24 release (checkout, setup-python, upload/download-artifact,
deploy-pages, upload-pages-artifact), each pinned by full commit SHA with
the reviewed version in a comment; the artifact inputs we use are
unchanged across the bump. A posture test fails if any action is ever
left unpinned by SHA (#179).
Fixed
- Deprecation cleanup.
verify_coverwrapreads pixels withImage.tobytes()
instead of the deprecatedImage.getdata()(removed in Pillow 14), with a
press-scoped warning-to-error filter so it cannot creep back (#167); the
async fixture loop scope is pinned tofunctionexplicitly, matching the
suite's isolation law and ending the pytest-asyncio default-drift warning,
proven by a loop-identity and task-leak test (#169). The site's Pandoc
--no-highlightdeprecation is already gone: the redesign turned
highlighting on and colors the tokens in CSS, so no deprecated flag is
passed (#170).