Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5c09933
ci(deps): move every codeql-action step to v4.37.9 and scorecard-acti…
Nizoka Oct 18, 2026
a01d7c4
feat(core): zipnative 1.1 parity — 106-export bridge, --zip64, --name…
Nizoka Oct 18, 2026
85d2165
fix(security): presentation-only config, strict invocation, finite bo…
Nizoka Oct 18, 2026
712af36
ci(supply-chain): four-job release, one gate, hardened workflows, rul…
Nizoka Oct 18, 2026
1843483
test(fuzz): seeded parser fuzzing, stricter compiler, veraZIP 1.1 syn…
Nizoka Oct 18, 2026
1c01e37
chore(release): 1.1.0
Nizoka Oct 18, 2026
e2e820e
fix(review): findings of the pre-PR correctness and security reviews
Nizoka Oct 18, 2026
aba500a
fix(security): strict switch values, bounded batch verify, mode-stric…
Nizoka Oct 18, 2026
d6d24c8
fix(control): --timeout fires while an input is stalled
Nizoka Oct 18, 2026
2a5cdc5
fix(contract): published schemas match the output, typed manifest, sa…
Nizoka Oct 18, 2026
6f147b6
chore(supply-chain): Node security floor, offline denylist, accurate …
Nizoka Oct 18, 2026
8d428ed
docs: second-review fixes to the contract docs, migration notes and A…
Nizoka Oct 18, 2026
0536020
feat(core): every zipnative export reachable — canonicalize, merge, -…
Nizoka Oct 18, 2026
887254f
fix(review): close the counter-verification findings of the 1.1.0 review
Nizoka Oct 18, 2026
f8d7f16
chore(agents): track the release-audit skill and the shared Claude Co…
Nizoka Oct 18, 2026
99bf8c3
chore(release): move the 1.1.0 review and triage reports out of the tree
Nizoka Oct 18, 2026
b04f15f
fix(audit): the confirmed findings of the 1.1.0 release audit
Nizoka Oct 18, 2026
ac8bd57
docs(release): the 1.1.0 audit verdict and the commit rows in the PR …
Nizoka Oct 18, 2026
9eaecd9
chore(release): release date 2026-10-20
Nizoka Oct 19, 2026
64089ac
fix(audit): the release-day round of the 1.1.0 audit
Nizoka Oct 19, 2026
a176252
docs(release): the release-day verdict, the triage re-read and the fi…
Nizoka Oct 19, 2026
37b017c
test(io): refuse a directory input from a private temp dir, not the t…
Nizoka Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
{
"attribution": {
"commit": "",
"pr": ""
},
"env": {
"BASH_MAX_OUTPUT_LENGTH": "16000",
"BASH_DEFAULT_TIMEOUT_MS": "300000",
"BASH_MAX_TIMEOUT_MS": "1800000",
"NO_COLOR": "1"
},
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npm test*)",
"Bash(npm ls *)",
"Bash(npm pack --dry-run*)",
"Bash(npm audit*)",
"Bash(npx vitest *)",
"Bash(npx tsc *)",
"Bash(npx eslint *)",
"Bash(node scripts/*)",
"Bash(node samples/run-all.js *)",
"Bash(node dist/cli.cjs *)",
"Bash(node -e *)",
"Bash(git status*)",
"Bash(git diff*)",
"Bash(git log*)",
"Bash(git show*)",
"Bash(git describe*)",
"Bash(git grep *)",
"Bash(git ls-files*)",
"Bash(git rev-parse *)",
"Bash(git merge-base *)",
"Bash(git check-ignore *)",
"Bash(git branch --list*)",
"Bash(git branch --show-current)",
"Bash(git worktree list*)",
"Bash(ls *)",
"Bash(wc *)",
"Bash(head *)",
"Bash(tail *)",
"Bash(sed -n *)",
"PowerShell(npm run *)",
"PowerShell(npm test*)",
"PowerShell(npm ls *)",
"PowerShell(npm pack --dry-run*)",
"PowerShell(npm audit*)",
"PowerShell(npx vitest *)",
"PowerShell(npx tsc *)",
"PowerShell(npx eslint *)",
"PowerShell(node scripts/*)",
"PowerShell(node samples/run-all.js *)",
"PowerShell(node dist/cli.cjs *)",
"PowerShell(node -e *)",
"PowerShell(git status*)",
"PowerShell(git diff*)",
"PowerShell(git log*)",
"PowerShell(git show*)",
"PowerShell(git describe*)",
"PowerShell(git grep *)",
"PowerShell(git ls-files*)",
"PowerShell(git rev-parse *)",
"PowerShell(git merge-base *)",
"PowerShell(git check-ignore *)",
"PowerShell(git branch --list*)",
"PowerShell(git branch --show-current)",
"PowerShell(git worktree list*)",
"PowerShell(ls *)",
"PowerShell(wc *)",
"PowerShell(head *)",
"PowerShell(tail *)",
"PowerShell(sed -n *)"
],
"deny": [
"Read(package-lock.json)",
"Read(coverage/**)",
"Read(dist/**)",
"Read(test-output/**)",
"Read(node_modules/**)",
"Read(samples/output/**)",
"Bash(npm publish*)",
"Bash(npm unpublish*)",
"Bash(npm deprecate*)",
"Bash(npm dist-tag*)",
"Bash(npm version*)",
"Bash(npx npm publish*)",
"Bash(git push --force*)",
"Bash(git push -f*)",
"Bash(git push *)",
"Bash(git push)",
"Bash(git tag -a*)",
"Bash(git tag -s*)",
"Bash(git tag -u*)",
"Bash(git tag -f*)",
"Bash(git tag -d*)",
"Bash(git tag -m*)",
"Bash(git tag --annotate*)",
"Bash(git tag --sign*)",
"Bash(git tag --force*)",
"Bash(git tag --delete*)",
"Bash(git tag v*)",
"Bash(gh pr create*)",
"Bash(gh pr edit*)",
"Bash(gh pr merge*)",
"Bash(gh pr close*)",
"Bash(gh pr comment*)",
"Bash(gh issue create*)",
"Bash(gh issue edit*)",
"Bash(gh issue close*)",
"Bash(gh issue comment*)",
"Bash(gh release *)",
"Bash(gh api *--method POST*)",
"Bash(gh api *--method PATCH*)",
"Bash(gh api *--method PUT*)",
"Bash(gh api *--method DELETE*)",
"Bash(gh api *-X *)",
"PowerShell(npm publish*)",
"PowerShell(npm unpublish*)",
"PowerShell(npm deprecate*)",
"PowerShell(npm dist-tag*)",
"PowerShell(npm version*)",
"PowerShell(npx npm publish*)",
"PowerShell(git push --force*)",
"PowerShell(git push -f*)",
"PowerShell(git push *)",
"PowerShell(git push)",
"PowerShell(git tag -a*)",
"PowerShell(git tag -s*)",
"PowerShell(git tag -u*)",
"PowerShell(git tag -f*)",
"PowerShell(git tag -d*)",
"PowerShell(git tag -m*)",
"PowerShell(git tag --annotate*)",
"PowerShell(git tag --sign*)",
"PowerShell(git tag --force*)",
"PowerShell(git tag --delete*)",
"PowerShell(git tag v*)",
"PowerShell(gh pr create*)",
"PowerShell(gh pr edit*)",
"PowerShell(gh pr merge*)",
"PowerShell(gh pr close*)",
"PowerShell(gh pr comment*)",
"PowerShell(gh issue create*)",
"PowerShell(gh issue edit*)",
"PowerShell(gh issue close*)",
"PowerShell(gh issue comment*)",
"PowerShell(gh release *)",
"PowerShell(gh api *--method POST*)",
"PowerShell(gh api *--method PATCH*)",
"PowerShell(gh api *--method PUT*)",
"PowerShell(gh api *--method DELETE*)",
"PowerShell(gh api *-X *)"
]
}
}
62 changes: 62 additions & 0 deletions .claude/skills/release-audit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
name: release-audit
description: Pre-release audit of zipnative-cli — two parallel auditors (claims vs code and the non-negotiables; help text, the surface tables, the engine-export map, samples, veraZIP and the release surfaces), an adversarial verifier, an agent-autonomy pass and a GO/NO-GO ledger under .audit/<version>/. Run by the maintainer before every release; never invoked by the model on its own.
disable-model-invocation: true
allowed-tools: Read, Grep, Glob, Bash(npm run *), Bash(npm ls *), Bash(npx vitest *), Bash(node scripts/*), Bash(node samples/run-all.js *), Bash(node dist/cli.cjs *), Bash(node -e *), Bash(git diff*), Bash(git log*), Bash(git show*), Bash(git describe*), Bash(git grep *), Bash(git check-ignore *), Agent
argument-hint: [release-notes/vX.Y.Z.md] [previous-tag]
---

# Release audit

Audit the release described by `$0` (default: the newest `release-notes/v*.md`) against everything that changed since `$1` (default: the previous `v*` tag from `git describe --tags --abbrev=0`, or the root commit for the first release). The audit produces findings, never fixes: every fix goes through the normal edit → gate loop afterwards, and the ledger records what was fixed.

Read `ledger.md` first for the ledger and verdict formats. Each phase below hands a template to the agents it spawns; the agents return findings, you file them.

## Ledger location

`.audit/<version>/` — git-ignored (check `git check-ignore -v .audit/<version>/x.md` prints the rule before writing; it is NOT under `test-output/`, which Claude Code is denied to Read), so nothing here is ever committed. One Markdown file per report: brief, auditor-a, auditor-b, verifier-1, auditor-d, verifier-2, then the ledger and the verdict (formats in `ledger.md`).

## Brief

Before Phase A, write `.audit/<version>/brief.md`: the criteria the release is judged on, the decisions already recorded (every ADR under `docs/adr/`, the deferred items in `ROADMAP.md`, the engine-side drafts under `.github/drafts/`) and the items a previous round settled. Every agent below receives the brief with its template, so a settled item is not re-filed — a finding that shows one of those decisions is *unsafe* stays admissible, and names the decision.

## Phase A and B — two auditors, in parallel

Spawn both with the Agent tool in the same message (distinct angles; neither sees the other's report):

- **Auditor A — claims vs code.** Template: `auditor-a.md`. Every claim in the release note and the top CHANGELOG entry is checked against `src/commands/`, `src/utils/`, `src/core-bridge/` and `tests/`; at least one assertion per claim is *reproduced with a command* (a test, a script, the BUILT binary `node dist/cli.cjs …`), not inferred from reading. Its brief includes the refusal posture and the non-negotiables of CLAUDE.md §Project philosophy (one runtime dependency, no ZIP parsing in `src/`, every engine import through the bridge, offline, no security default loosened, a symlink never materialised, `--deterministic` bytes never post-processed).
- **Auditor B — help text, the surface tables and the release surfaces.** Template: `auditor-b.md`. Every command's `--help` against `COMMANDS` in `src/commands/completion.ts` and the flag tables of `src/utils/flags.ts`, `schema manifest`, the engine-export map `docs/data/core-exports.json` and KB §8, `docs/data/errors.json`, the samples (`samples/run-all.js`) and the veraZIP corpus, the README, AGENTS.md and llms.txt, the publish workflow, the CHANGELOG, the release note and the governance files — every surface a human, an agent or the release pipeline reads — compared with the behaviour that actually shipped.

Both write their report in the finding format of `ledger.md` (id, severity, claim, evidence command, observed, expected).

## Phase C — adversarial verifier

Spawn one verifier (template: `verifier.md`) with both reports. It re-derives every finding from scratch — re-runs the evidence command, reads the cited lines — and stamps each one `CONFIRMED | DOWNGRADED | REJECTED | DUPLICATE` with a one-line justification. Auditors have about 10 % false findings; the verifier exists to keep them out of the ledger. A finding the verifier cannot reproduce is `REJECTED`, not "probably fine".

## Phase D — agent-autonomy pass, then verify

**The mechanical half is `npm run gate`; do not re-derive it.** That every command of `COMMANDS` has a USAGE block naming every flag it declares, that the README and the knowledge base list the same commands and flags, that every runtime export of zipnative is mapped in `docs/data/core-exports.json` and KB §8 and re-exported by the bridge (`tests/docs/consistency.test.ts`), that `schema manifest` publishes what `--help` declares (the gate's `smoke` step), that every sample still runs (`samples`, 96 jobs) and that every archive the CLI writes is conformant (`verazip`, `verazip-validate`) is decided on every run. Cite the test or the gate step instead of re-deriving it.

Spawn Auditor D (template: `auditor-b.md`, section "Autonomy pass") for what no test can decide: *can an agent that has only the published surfaces (`zipnative --help`, `zipnative <command> --help`, `zipnative schema manifest | errors | <subject>`, `zipnative doctor`, the README, AGENTS.md, llms.txt and `samples/`) drive every feature the release note names without reading `src/`?* Is each sentence of the help text true, is the advice still the best advice, and after a provoked failure do `error.remedy` in the envelope and the `cli.remedy` of that code in `schema errors` tell the agent what to do next? Then a second verifier pass (template: `verifier.md`) over its findings.

## Phase E — GO / NO-GO

Merge the confirmed findings into the ledger, then write the verdict file (both formats are in `ledger.md`):

- **GO** — no CONFIRMED finding of severity `blocker`; every `major` has a fix commit or an explicit maintainer waiver in the ledger.
- **NO-GO** — otherwise. List the blockers first, each with its evidence command, so the fix loop starts from the ledger, not from memory.

Report the verdict, the counts per severity and per stamp, and the ledger path. Do not push, tag, open a PR or publish: the maintainer takes over from `GO` — squash-merges the `release/vX.Y.Z` pull request, publishes the GitHub Release (which creates the tag), and `.github/workflows/publish.yml` publishes to npm.

## Known blind spots

Add a check for each of these to the auditor briefs; they are where an audit of a CLI over an engine misses something.

- Help text drifts from the tables: a flag added to `COMMANDS` (`src/commands/completion.ts`) or to `COMMAND_BOOLEAN_FLAGS` (`src/utils/flags.ts`) but described with a stale default or a false sentence in `src/index.ts` passes `tests/docs/consistency.test.ts`, which proves presence, not truth.
- The export map is generated (`npm run sync:engine`; `--check` runs in the gate only when an engine checkout is present): a map regenerated after the code but never reviewed proves consistency, not correctness. Read the `via` of each export the release adds against the command that claims it.
- `samples/run-all.js` asserts byte identity only for the deterministic and stream-parity jobs; a behaviour change on a flag no sample exercises is invisible to it. The veraZIP corpus carries no committed digest list of the previous release: byte identity with it is a comparison the maintainer prepares (`.audit/<version>/corpus-<previous>.sha256`, auditor-a.md §4).
- The non-negotiables are negative properties: no test looks everywhere for a second dependency, a `PK` signature parsed in `src/`, a socket, a symlink written to disk or a post-processed `--deterministic` byte unless one looks for it. Each needs its command (auditor-a.md §4).
- Refusal posture: a config file must not relax a check (`CONFIG_KEYS` in `src/utils/config.ts` is presentation-only), a switch value must be strict (`--flag=flase` and `ZIPNATIVE_*=flase` are usage errors), `--codec` is argv-only and a manifest needs `--allow-codec-load`. Try each from a planted `.zipnativerc.json`, the command line, the environment and a manifest task, not only from the tests.
- CI assumptions live outside the repo: Trusted Publishing needs the `npm-publish` environment, the `release: published` trigger and the npm client `publish.yml` pins by SHA-512; `tests/tools/workflows.test.ts` pins the file's shape, not the GitHub or npmjs settings. A green local gate proves nothing about the publish job.
- Auditors have ~10 % false findings — never file an unverified finding, and never let a `REJECTED` one reach the verdict.
- `.claude/settings.json` denies the shell tools `npm publish`, `git push`, `git tag` and the `gh` writes (`pr`, `issue`, `release`, `api --method POST`). An auditor never needs them: a finding is a row in a file under `.audit/`, written with Write or Edit — never a GitHub write (`.github/AGENT_RULES.md`).
Loading
Loading