Repository navigation
Nen v0.22.0
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 deliveries: #411 (closes #341), #412 (closes #348), #413 (closes #410), #414 (closes #404), #422 (closes #405).
The compatibility floor moves to 0.22. No delivery adds or removes a verb; the documented count stays 134.
Added
- parse —
nen parsegains 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/gptis refused rather than read as free text).--jsonaddsalternativeanditemsonly where they apply (#413, closes #410). - backlog, report —
nen backlog fetchandnen report datagain a repeatable--label(AND over an effort's issue and PR labels) and a--severity <name>[+]band, read from--severity-familyand--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 keepsissueCount/prCountas fetched (before the filter) and adds afilterkey; a filteredreport datakeeps every object of a kept effort, appendsobjectsFilteras its last key (with or without--register), refuses a filter given no objects source, and refuses at exit 2 a--registerdesk naming an object the filter removed.backlog orderandreport renderrefuse the filter flags (#413). - release, pr —
release.unitPathsaccepts{ "path": "<exact text file>", "lines": ["<whole-line regex>"] }entries.release unit-checkandpr merge --release-unitcheck 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;linedPathsandlineScopedViolationsare additive fields (#412, closes #348). - schema —
schema checkreportsnen/workflow.json#release, including exact, prefix/glob, key-bound and line-bound counts (#412).
Fixed
- release — an
=pathstring claims one exact path, so=README.mdcannot admitREADME.md/**. Nen's own release unit bounds changed lines insrc/version.ts,README.mdanddocs/USAGE.mdto version/floor and declared install/example forms, and names=CHANGELOG.mdexactly. 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-filerefuses a message missing every agent trailer admitted bycommits.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", andv0.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 whosedependency.minimumis below0.22is refused at exit 5 by this build: raise it to"0.22"and movepinned_reftov0.22.0. zheref/hatsu is the consumer to repin; its declarations passschema checkunder this build unchanged (checked 2026-10-18), and zheref/hatsu#297 follows the repin. - parse — a
--grammartemplate 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.scopesand 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_patternmust name one anchored literal[bot]login, one literal-botlogin, 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 throughschema checkon 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.allowedAttributionTrailersmust 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.jsonnow usesrelease.unitPaths[].lines, which a0.21.xbinary refuses: run nen verbs in this checkout from a0.22build.