Skip to content

Nen v0.22.0

Choose a tag to compare

@zheref zheref released this 18 Oct 17:14
· 151 commits to main since this release
46d333b

v0.22.0 — 2026-10-18

Release unit for v0.21.0..v0.22.0. It brings list slots and alternations in nen parse with a label and severity filter on the backlog reads, line-bound release units, hardened declared inputs, an agent-trailer requirement on wc squash, and the runner preflight refreshed from Hatsu:

The compatibility floor moves to 0.22. No delivery adds or removes a verb; the documented count stays 134.

Added

  • parse — nen parse gains list slots (<slot>{+}, <slot>{&}; every item of an enumerated list is checked) and alternations (<a:..>{+}|<b:..>[+]|<c>; the free alternative is taken only when no piece of the value is an enumerated value, so @g4+model/gpt is refused rather than read as free text). --json adds alternative and items only where they apply (#413, closes #410).
  • backlog, report — nen backlog fetch and nen report data gain a repeatable --label (AND over an effort's issue and PR labels) and a --severity <name>[+] band, read from --severity-family and --severity-order. An undeclared label, or a piece of a declared label containing &, is refused at exit 2 before any read; a filter that keeps nothing is an explicit zero at exit 0; an unfiltered document is unchanged. A filtered fetch keeps issueCount/prCount as fetched (before the filter) and adds a filter key; a filtered report data keeps every object of a kept effort, appends objectsFilter as its last key (with or without --register), refuses a filter given no objects source, and refuses at exit 2 a --register desk naming an object the filter removed. backlog order and report render refuse the filter flags (#413).
  • release, pr — release.unitPaths accepts { "path": "<exact text file>", "lines": ["<whole-line regex>"] } entries. release unit-check and pr merge --release-unit check every removed and added line against complete merge-base/head blobs, failing closed on unreadable text or a diff beyond the stated work bounds. Existing JSON-key bounds keep their report shape; linedPaths and lineScopedViolations are additive fields (#412, closes #348).
  • schema — schema check reports nen/workflow.json#release, including exact, prefix/glob, key-bound and line-bound counts (#412).

Fixed

  • release — an =path string claims one exact path, so =README.md cannot admit README.md/**. Nen's own release unit bounds changed lines in src/version.ts, README.md and docs/USAGE.md to version/floor and declared install/example forms, and names =CHANGELOG.md exactly. Both removed and added lines are checked independently; allowed lines may be deleted, moved or replaced by another allowed form, including optional fixed command fragments. The bound does not preserve presence, position, pairing or consistent versions (#412).
  • release — line bounds use a release-only bounded state matcher, preserving legacy identity-regex consumers. Unsupported syntax fails schema loading by pointer. Matching never backtracks through PR text; source, nesting, state, class and pattern-count limits bound compilation, and changed-line length plus per-line/per-file operation budgets fail closed with a distinct exhaustion reason. The limits and supported expression subset are documented in USAGE (#412).
  • schema, report — exact markers in review scopes and report tiers are validated at their read seams, so an empty = or malformed repo-relative exact path cannot silently claim nothing. Bare prefixes and globs retain their existing meaning (#412).
  • schema — lane cwd paths share stdoutTo's repository-relative validation, including Windows absolute, drive-relative and traversal spellings on every host. Dependabot review exemptions name one anchored literal bot account rather than a catch-all or human-shaped regex (#414, closes #404).
  • pr — threads settle scans every inline and file body before any GitHub call for GitHub/URL credentials, AWS access keys, Google API keys, Azure account keys, private-key headers and high-entropy tokens. Refusals name the shape and redact the value. A URL authority's numeric port followed by an @ in its path, query or fragment no longer reads as a password (#414).
  • gates — NEXT_RELEASE is derived as VERSION's next minor; release proposals need no separate edit to gates.ts (#414).
  • reports — Nen declares final/register sections for Hatsu's Rikugan template (#414).
  • wc — wc squash --message-file refuses a message missing every agent trailer admitted by commits.allowedAttributionTrailers, at exit 2 before reset or commit, naming the keys and policy source (#422, closes #405).
  • runner — the runner preflight fixture and Nen's Windows workflow are refreshed from Hatsu 0.111.2: branch-only pushes stop release tags waking the pool, and Windows tool resolution uses the runner service's recorded PATH. Each pool keeps its own label and SHA-pinned checkout (#411, closes #341).

Breaking / consumer notes

  • Repin: "0.21" → "0.22", and v0.21.0 → v0.22.0. The floor moves because changes in #412, #413, #414 and #422 alter meaning on unchanged inputs (the notes below). A repository whose dependency.minimum is below 0.22 is refused at exit 5 by this build: raise it to "0.22" and move pinned_ref to v0.22.0. zheref/hatsu is the consumer to repin; its declarations pass schema check under this build unchanged (checked 2026-10-18), and zheref/hatsu#297 follows the repin.
  • parse — a --grammar template that used | or {…} outside <…> as literal text changes meaning: | there is now an alternation (refused when it cannot resolve), and {…} declares a list joiner on the slot before it, so <a> {x} <b> leaves <b> without a separator and drops it silently (exit 0, ok: true) until #419 refuses that shape. No Hatsu template uses either form (#413).
  • release, review, report — = is an explicit exact-path marker in the shared path grammar (release.unitPaths, review.scopes and report tiers). Bare strings retain their prefix/glob meaning; a literal path beginning = can be named with another leading =. Content-entry paths now also refuse globs, empty or dot segments, backslashes and control characters. A line-bound file must be readable as UTF-8 without NUL at the same path at both commits; additions, deletions and renames that cannot satisfy that check are refused (#412).
  • schema — a lane traversal is now rejected while loading the schema: a shu invocation exits 1 for the malformed declaration, where it formerly reached runtime containment at exit 2. No subprocess runs in either case; filesystem/symlink containment still runs at use (#414).
  • schema — lane cwd declarations that are empty, absolute, drive-relative, contain a parent segment or a glob now fail at their own pointer. A dependabot_carve_out.author_pattern must name one anchored literal [bot] login, one literal -bot login, or the legacy dependabot/renovate account (those latter forms also admit an optional [bot] suffix). Regex alternation, wildcard bot sets and human-shaped names are refused. Consumers see these new validator refusals through schema check on repin (#414).
  • pr — the shared content scanner is heuristic: its entropy rule flags base64-like tokens of at least 32 characters, at least three character classes and Shannon entropy at least 4.5 bits per character. Hex hashes and low-entropy text do not meet that rule; a shape it does not know can pass. Only threads settle currently calls it (#414).
  • wc squash — repositories with a nonempty commits.allowedAttributionTrailers must include one of those trailer keys with a value in the squash message's final paragraph. Previously an otherwise valid message without an agent trailer could be squashed. Empty or absent policy is unchanged; forbidden-trailer and post-commit injection checks remain separate (#422).
  • nen's own release unit — this repository's nen/workflow.json now uses release.unitPaths[].lines, which a 0.21.x binary refuses: run nen verbs in this checkout from a 0.22 build.