Skip to content

Releases: clintecker/press

press v2.3.1

Choose a tag to compare

@clintecker clintecker released this 25 Jul 02:40

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 by press 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-print refused 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 in description (or as a
    cover.emblem) and not as an explicit cover.subject, press cover fell
    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's description, then cover.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 outside press.adapters holds a direct subprocess
    or environment call matched only the subprocess.Popen attribute form; from subprocess import Popen and import subprocess as sp slipped 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 into press.adapters (its streaming sibling of SubprocessRunner)
    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

Choose a tag to compare

@clintecker clintecker released this 25 Jul 00:06

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 enhance finishes 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 in config/aesthetic.yaml drives the model and the
    palette. The upscaler is a detected external tool (Upscayl's upscayl-bin
    or a standalone realesrgan-ncnn-vulkan), reported by press 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 doctor report -- 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 *.jpg only, so an enhanced book silently lost its List of Plates
    and its plate verification; they now resolve through one booklib.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 / check with 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, so press lookup issn counted 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_ink and verify_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

Choose a tag to compare

@clintecker clintecker released this 24 Jul 20:28

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 about Content-Length decided how much memory
    a lookup spent before the cap could refuse it. The bound now travels with
    the request: adapters.http.urlopen_transport takes an optional
    max_bytes and 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 as data-label by
    webmeta.label_table_cells when 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's overflow:hidden zeroed 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

Choose a tag to compare

@clintecker clintecker released this 24 Jul 17:52

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> and press 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. With registrations.lccn or
    registrations.issn configured, 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 reconciles roadmap/milestones.json and ROADMAP.md against the
    live GitHub milestones after a merge to main (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.py is 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 no site-url ships no falsely-canonical output.
    The book site also gains a sitemap.xml and robots.txt, emitted only
    when a site-url is configured. verify_pages gains check_metadata and
    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_coverwrap family -- route every process, environment,
    and tool-probe call through the typed adapters. The boundary gate's legacy
    allowlist is deleted, so a direct subprocess / os.environ /
    shutil.which call is now refused anywhere outside press.adapters, and
    the import-side-effect sandbox moved to adapters/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.yaml is the one
    canonical source; src/press/data/providers.yaml is a deterministic
    projection of it (a fixed banner, then the canonical bytes verbatim),
    regenerated by press 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

Choose a tag to compare

@clintecker clintecker released this 24 Jul 01:29

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 by press cover and 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 by plates.style; --from turns real source
    material (a photograph the author took, a rough map) into a house-format
    plate. Installed through press 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 verify on 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
    classified producer in the surface inventory is now held, by the selftest,
    to an entry in PRODUCER_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-toolchain is now built
    and smoked on native runners for both linux/amd64 (CI) and linux/arm64
    (Apple Silicon), assembled into a manifest list; local Docker PDF builds on a
    Mac run natively instead of dying under qemu. build.yml pins 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 \textwidth by
    \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 supplied config/front-matter.yaml, so a book
    with a cover.jpg and 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, and verify_pdf refuses 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 crashed press selftest on 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

Choose a tag to compare

@clintecker clintecker released this 22 Jul 03:38

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.jpg and 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_coverwrap now 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 \PressDropCap macro (built on
    lettrine, with a needspace guard so a chapter opening is never stranded
    at the foot of a page); for HTML and EPUB it emits semantic
    chapter-opening/drop-cap spans 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 own chapter-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 in test_dropcaps and
    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 under examples/ — 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 passes press 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 onix generates 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 an EA product), the ISBN as ProductIDType 15, 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 pcn assembles the Library of
    Congress PrePub Book Link field values (dist/<slug>-pcn.txt) for the LCCN
    application, flagging any gap the form needs. New registrations helpers
    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 — while novella-5x8 becomes 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
    digest over its design-affecting data, so a sealed value cannot change
    without the key that scopes its visual baseline moving; a new
    INV-profile-geometry proves 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.txt and 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; apply writes 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-safe and INV-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's conformance gate
    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 by INV-extension-conformance and
    INV-extension-seal, proven by check_extension_conformance over 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 @v2 to opt in, and a @v1 book 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), and print.provider select the rest. Trim is
    derived from the profile, not hand-entered; the INV-config-trim invariant
    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 record docs/PRINT-PROFILES-PLAN.md.

press v1.20.0

Choose a tag to compare

@clintecker clintecker released this 21 Jul 21:11

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 in site/brand/.
  • CLI branding (press.brand): a running press with no command shows the
    block banner and tagline, and press all ends with a "your book is ready"
    line, in the house vermilion. Color is emitted only to a real terminal
    (honoring NO_COLOR/FORCE_COLOR), so piped output stays plain and
    scriptable.

press v1.19.1

Choose a tag to compare

@clintecker clintecker released this 21 Jul 18:51

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 as registrations.isbn-block: {prefix, size}, and
    press isbn assign print|epub mints the next unused ISBN-13 from it —
    computing the check digit, hyphenating with the agency's own prefix
    hyphenation, and writing it to registrations.isbn. press isbn status
    shows what is used and free; a malformed block fails press 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 adds registrations.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 doctor treats 3.14 as
    in-range, and the installation and compatibility docs name the 3.10-3.14
    range (#168).
  • A scheduled Repository metadata workflow asserts the repository's
    discovery configuration cannot silently drift: the homepage points at the
    docs site, the default branch is main, 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): the print target 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 at build/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 config commands 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

Choose a tag to compare

@clintecker clintecker released this 21 Jul 01:07

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.org Book JSON-LD node (name, authors, publisher, description,
    date, and the available editions as workExample). Nothing is invented --
    a canonical URL, og:url, and cover image appear only when a site-url
    (and cover) is configured, so an offline build never claims a false
    canonical. press verify fails 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 in main and gets no start-reading block (#160).
  • Git subprocesses observe only their own repository. A git commit runs
    its hooks with GIT_INDEX_FILE (and GIT_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-binding GIT_* 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 commit hook without a workaround (#176).

press v1.17.0

Choose a tag to compare

@clintecker clintecker released this 20 Jul 21:47

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-maintainer GOVERNANCE.md covering decision/release/security
    authority and bus-factor (#164); and scripts/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 deterministic sitemap.xml
    and robots.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 one main landmark, 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_coverwrap reads pixels with Image.tobytes()
    instead of the deprecated Image.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 to function explicitly, 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-highlight deprecation is already gone: the redesign turned
    highlighting on and colors the tokens in CSS, so no deprecated flag is
    passed (#170).