Skip to content

Port the post-v0.229.0 development train - #71

Merged
kapoorankush merged 1 commit into
masterfrom
port/v0.230.0
Sep 22, 2026
Merged

kapoorankush merged 1 commit into
masterfrom
port/v0.230.0

Conversation

@kapoorankush

Copy link
Copy Markdown
Owner

Ports the litclock-dev train that landed after v0.229.0.

Boundary confirmed by content, not by the previous port's stated range: dev
7438f611 <-> public 49083e3d (tag v0.229.0). Eight non-stats commits, seven
files, and seven of those eight commits are tests or documentation.

The runtime change — litclock-dev#886

The whole runtime delta is one degradation arm in _runtime_render_enabled().

A validation marker that is not valid UTF-8 used to kill the painter instead of
falling back to the pre-rendered images. open(..., encoding="utf-8") defers
decoding to .read(), and a UnicodeDecodeError is a ValueError, so the
except OSError beside it never caught one and the exception propagated out of
a guard whose entire contract is to return True or False. Every other input to
that guard already degraded — a missing marker, an unusable freetype-py wheel, a
stale FreeType version, a digest that no longer matches the device's proof
inputs. A corrupt one was the exception, and it is the shape a power loss
mid-stamp or a damaged card leaves behind.

Reachable only where LITCLOCK_RUNTIME_RENDER is true, which is not nobody: the
fielded clock runs with it on, so this was live in production rather than
latent.

Reproduced against the code this release replaces. On a bench device
tracking this repo at v0.229.0, a corrupt marker produced UnicodeDecodeError
at literary_clock.py:600 and exit 1; the same marker with the fixed
src/literary_clock.py logged a warning naming the file and the re-stamp
command, fell back to the PNG tier, and exited 0. The control failed first,
which is what makes the fixed run evidence.

Not covered: the SPI write. --dry-run exits before epd.init(), so this
proves the render path and the fallback decision, not the panel.

Test infrastructure

  • litclock-dev#881 — unit tests can no longer resolve a hostname.
    tests/conftest.py wraps socket.getaddrinfo at import (not as a fixture,
    which would be subject to the very ordering it defends against), refuses
    anything but loopback, and fails the run from pytest_sessionfinish rather
    than merely reporting. New file tests/test_network_guard.py.
  • litclock-dev#883 — the self-test record's duration_s had no value
    coverage; the old 0 <= duration_s < 5 band was satisfied by a hardcoded
    0.0.

Held back

litclock-dev#871 Stage B, the runtime-render migration, is not in this train.

Port mechanics

  • git apply -3 from the dev range. One conflict, in CLAUDE.md, where public
    already carried a paragraph the dev side adds four more before. Resolved to
    dev's ordering; the requalifier then reproduces public's existing line.
  • Issue refs requalified on ported lines only and validated by this repo's
    own tests/test_issue_ref_namespace.py, not by a hand regex. That test caught
    the #860/#864 and #879/#881 continuation forms my regex let through.
  • Maintainer-local paths stripped. Public master carries zero
    ~/archives/... references and does not record the bench address; the ported
    QA prose is rewritten to master's existing convention.
  • The CHANGELOG gets one line. The other seven commits are test
    infrastructure and engineering-record corrections that an owner cannot see.

Checks

ruff check . clean (whole repo). pytest tests/ --ignore=tests/test_eink_display.py:
4697 passed, 66 skipped. No shell scripts touched, so shellcheck is not
implicated. Reviewed cross-model twice, the second time at the branch's final
HEAD because round one's fixes were themselves unreviewed.

Boundary confirmed by content: litclock-dev `7438f611` <-> public `49083e3d`
(tag v0.229.0). Eight non-stats commits, seven files.

Seven of eight files are tests or documentation. The entire runtime delta is a
degradation arm in `_runtime_render_enabled()` (`src/literary_clock.py`).

### The runtime change (litclock-dev#886)

A validation marker that is not valid UTF-8 used to kill the painter instead of
falling back to the pre-rendered images. `open(..., encoding="utf-8")` defers
decoding to `.read()`, and a `UnicodeDecodeError` is a `ValueError`, so the
`except OSError` beside it never caught one and the exception propagated out of
a guard whose whole contract is to return True or False. Every other input to
that guard already degraded: a missing marker, an unusable freetype-py wheel, a
stale FreeType version, a digest that no longer matches. A corrupt one was the
exception, and it is the shape a power loss mid-stamp or a damaged card leaves.

Reachable only where `LITCLOCK_RUNTIME_RENDER` is true, which is not nobody:
the fielded clock runs with it on, so this was live in production rather than
latent. Reproduced on the bench against the code this release replaces
(`UnicodeDecodeError` at `literary_clock.py:600`, exit 1) and confirmed to
degrade to the PNG tier at exit 0 with the fix.

### Tests

- litclock-dev#881 — unit tests can no longer resolve a hostname. `conftest.py`
  wraps `socket.getaddrinfo` at import, refuses anything but loopback, and
  fails the run from `pytest_sessionfinish`. New file `tests/test_network_guard.py`.
- litclock-dev#883 — the self-test record's `duration_s` had no value coverage;
  the old `0 <= duration_s < 5` band was satisfied by a hardcoded `0.0`.

### Not in this train

litclock-dev#871 Stage B (the runtime-render migration) is held.

### Checks

`ruff check .` clean. `pytest tests/ --ignore=tests/test_eink_display.py`:
4697 passed, 66 skipped. Issue refs requalified on ported lines only and
validated by `tests/test_issue_ref_namespace.py`. No shell scripts touched.

CHANGELOG gets one line: the other seven commits are test infrastructure and
engineering-record corrections that an owner cannot see.
@kapoorankush
kapoorankush merged commit 227549a into master Sep 22, 2026
6 checks passed
@kapoorankush
kapoorankush deleted the port/v0.230.0 branch September 22, 2026 20:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant