Skip to content

release: 0.6.1 — Layer-1/2/3 ('give the user a chance')#33

Merged
maltsev-dev merged 1 commit into
masterfrom
release/0.6.1
Jun 24, 2026
Merged

release: 0.6.1 — Layer-1/2/3 ('give the user a chance')#33
maltsev-dev merged 1 commit into
masterfrom
release/0.6.1

Conversation

@maltsev-dev

Copy link
Copy Markdown
Member

Summary

Bumps version 0.6.00.6.1 and adds the release-notes entry.
The functional work landed in the merged PRs #31 (Layer-1) and
#32 (Layer-2/3); this PR is the release label + CHANGELOG.

What's in 0.6.1

All three layers of the "give the user a chance" design, on top of
the 0.6.0 P0 hardening pass:

Layer What Public API
1 — structured exception hierarchy NullRunError base + 5 typed subclasses (ConfigError, AuthError, BackendError, BudgetError, ToolBlockedError) with error_code / user_action / retryable / docs_url / cause nullrun.NullRunError, NullRunAuthError, NullRunConfigError, NullRunBackendError, NullRunBudgetError, NullRunToolBlockedError, WorkflowKilledInterrupt
2 — global error hook nullrun.on_error(hook) fires for every structured NullRunError before it propagates; multiple hooks fire in registration order; hook exceptions are caught and logged at DEBUG; has_hooks() short-circuit keeps the hot path zero-cost nullrun.on_error
3 — runtime snapshot nullrun.status() returns a frozen NullRunStatus dataclass with one of four headline states (ok / degraded / offline / misconfigured); raises NullRunConfigError (NR-C004) if no runtime has been init()'d; never lazily creates a runtime nullrun.status

Per-code docs: docs/errors/ (15 per-code pages + README index).

TestPyPI yank — manual step (REQUIRED before re-running publish)

The previous 0.6.0 on TestPyPI (uploaded 2026-06-23, before #31
and #32 landed) cannot be silently overwritten — TestPyPI rejects
400 File already exists for any filename reuse regardless of
content hash (see https://test.pypi.org/help/#file-name-reuse).

The publish-test workflow must yank the existing 0.6.0 first.
Easiest path — web UI:

  1. Go to https://test.pypi.org/project/nullrun/0.6.0/#history
  2. Click ManageYank release
  3. Confirm

After the yank, re-run Actions → publish-test → Run workflow on
master (or wait for this PR to merge and run on master).

If you prefer the CLI (requires a TestPyPI API token with
project scope — not stored in this repo's secrets, only
Trusted-Publishing is wired):

pip install twine
twine yank nullrun -r testpypi -v 0.6.0

Verification (already done locally on master HEAD)

Check Result
pytest 926 passed, 13 skipped
ruff check src/ tests/ All checks passed
mypy src/ No issues found in 26 source files

Files in this PR

  • pyproject.tomlversion = "0.6.1"
  • src/nullrun/__version__.py__version__ = "0.6.1"
  • CHANGELOG.md## [0.6.1] — 2026-06-24 entry

After merge

  1. Yank 0.6.0 on TestPyPI (web UI; see above).
  2. Re-run publish-test workflow on master.
  3. Verify the new 0.6.1 upload succeeds:
    pip install -i https://test.pypi.org/simple/ nullrun==0.6.1.

Bump version 0.6.0 → 0.6.1. This release lands all three layers
of the 'give the user a chance' design on top of the 0.6.0 P0
hardening pass:

  * Layer 1 — structured exception hierarchy. Every public SDK
    exception inherits from NullRunError and carries
    error_code / user_action / retryable / docs_url / cause.
    Five new typed classes (NullRunConfigError, NullRunAuthError,
    NullRunBackendError, NullRunBudgetError, NullRunToolBlockedError)
    are subclasses of the existing user-facing classes, so every
    'except' clause from 0.6.0 keeps matching.

  * Layer 2 — nullrun.on_error() global error hook. Fires for
    every structured NullRunError before the exception
    propagates. Skipped for WorkflowKilledInterrupt (BaseException
    subclass — kill is a signal, not an error). Multiple hooks
    fire in registration order; hook exceptions are caught and
    logged at DEBUG. has_hooks() short-circuit keeps the hot
    path zero-cost when no hook is registered.

  * Layer 3 — nullrun.status() introspection. Synchronous,
    thread-safe, side-effect-free snapshot of runtime state.
    Returns a frozen NullRunStatus dataclass with one of four
    headline states (ok / degraded / offline / misconfigured).
    Raises NullRunConfigError (NR-C004) if no runtime has been
    init()'d — never lazily creates a runtime as a side effect.

Per-code docs in docs/errors/ (15 pages + README index).
New tests pin the hierarchy, the hook semantics, the snapshot
fields, and the recent-errors ring buffer.

TestPyPI: the previous 0.6.0 (uploaded 2026-06-23, before
#31 and #32 landed) is yanked separately so the new 0.6.1
wheel can be uploaded. The yank is a TestPyPI-side action;
it does not change the source tree.
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@maltsev-dev maltsev-dev merged commit 54cc6fa into master Jun 24, 2026
5 checks passed
@maltsev-dev maltsev-dev deleted the release/0.6.1 branch June 24, 2026 11:04
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