[v0.1/Release] Cut and publish v0.1.0 from the gated revision #31
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis#31
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent: #12 (Release completion). Depends on every P0 and P1 child tracked there.
Why
The first public contract is defined by the exact source revision, generated schemas, documentation, and artifact that are tagged together. Passing gates on a nearby revision is not sufficient.
Scope
skills/felis/CHANGELOG.mdcascade.v0.1.0tag and publish immutable references and the Linux artifact.Acceptance criteria
just check, schema/proto/compatibility gates, and the supported Linux smoke/publish gate pass on that commit.Triage plan (2026-09-03)
Source-grounded triage against
mainat69076d42, reviewed through seven rounds of an independent reviewer (pisol/luna) until it passed with no findings. The dependency order that supersedes the tracker's is posted on #12. Where a "Review amendments" section below conflicts with an earlier section, the amendment is the decision.Claim check
The issue is a procedure, not a code claim; its premises check out with two corrections.
git tagempty;CHANGELOG.md:14is the only## [header.CHANGELOG.md:11-12anddocs/reference/workspace.md:157-176describe the pre-release versioning stance the release commit has to close out.Cargo.toml:5-14[workspace.package]hasedition,rust-version,license,repository,publish, but noversion; each of the eleven crates setsversion = "0.1.0"itself (crates/*/Cargo.toml:3).nix/package.nix:57-59reads the version fromcrates/felis-cli/Cargo.tomlonly. So either #31 moves the crates toversion.workspace = true(a small mechanical change that makes the "set the version" step one line) or the wording changes to "set every crate's version". Recommend the former, done before the release commit so the release diff is only the number.just check(justfile: fmt-check + clippy + nextest + deny) mirrorspr.yml:31-43; the schema gate ispr.yml's--all-featuresnextest run through the schema sync test (crates/felis-client-core/src/config.rs:2476,just schema); the proto codegen gate ispr.yml:45-63; the Linux smoke/publish gate ispr.yml:366-477. The "compatibility gate" the issue names does not exist yet (see #19 report: the pre-commit hook is skipped in the sandbox), and the tag trigger does not exist (see #18). Both are prerequisites, as the tracker says.crates/build-common.rs:5-33), the docs package (flake.nix:252-262,.#docs) carries no version, and the schema file (crates/felis-client-core/felis-config.schema.json) has no version stamp. Without #17 this criterion cannot be checked mechanically.skills/felis/CHANGELOG.md): help/completions/man are generated from clap at package time (nix/package.nix:120-134), so "current" means the clap definitions are final; the schema is a committed file with a sync test;skills/felis/SKILL.mdis hand-maintained and product-shipped (CLAUDE.md"Skills"), so it is the one surface a grep sweep must cover.Post-snapshot commits (
8a82e069,5a1a49a2,69076d42) are user-affecting (config key rename, CLI separator) — verify they each have aCHANGELOG.mdUnreleased entry during the sweep (I did not verify this; add it to the checklist).Verdict
accept-with-changes. Keep it as the terminal issue, but (1) replace "inherited workspace version" with the
version.workspace = truemigration as a pre-step, (2) add the two rehearsal outputs from #18 (green rc tag, red mismatch tag) as acceptance evidence, and (3) split the "cross-repository consistency sweep" into a concrete grep list so it is not open-ended on release day.Approach
Ordered checklist for the release commit and tag; every step is something the human runs or a CI run URL to record in the issue.
Pre-step (own commit, before the release commit)
Cargo.toml: addversion = "0.1.0"under[workspace.package]; eachcrates/*/Cargo.toml:3→version.workspace = true.nix/package.nix:59keeps readingfelis-cli's manifest (it resolves throughlib.importTOML? No —importTOMLon the crate file will now seeversion = { workspace = true }, not a string). Change it to read the workspace../Cargo.toml.workspace.package.version. Add a unit-ish check injust release-check(#18) thatnix eval --raw .#felis.versionequals the tag.docs/reference/workspace.md:167-176"Versioning": say the crate version is workspace-inherited and floats together (the prose already says "float together").Release commit (
chore(release): v0.1.0)just schema(no diff),just proto(no diff),felis __mangen/completionsare build-time so nothing to commit; runjust check.CHANGELOG.md: rename## [Unreleased]→## [0.1.0] - 2026-MM-DD, add a fresh empty[Unreleased]above, fix the sentence at:11-12("until a first release is tagged"), add the Keep-a-Changelog link footers ([Unreleased]: …/compare/v0.1.0...HEAD,[0.1.0]: …/releases/tag/v0.1.0).docs/reference/workspace.md:164-166("until the compatibility freeze the dev wire carries no promise"),docs/reference/ipc.md:1685-1687,docs/how-to/update-felis.md:99("first tagged release"),docs/how-to/install.md:143,154andREADME.md:20,23(tag-pinned flake refs, per #18). Grep sweep terms:Unreleased,first release,first tag,compatibility freeze,each \main` revision,git+https://git.natsukium.com/natsukium/feliswithout?ref=`.skills/felis/SKILL.md: any verb/flag added by the P1 CLI issues (#20, #23, #25, #26, #27, #53, #54, andfelis versionfrom #17) appears with its--formatshape; run the skill's examples against the built binary once.x86_64-linuxininstall.md:130-146,workspace.md:276-281, README; Windows stays "CI evidence".Gates on the exact commit
main; wait forpr.ymlfully green includinglinux-publishandproto-compat(#19). Record the run URL.just release-check v0.1.0(#18) on a clean tree (git status --porcelainempty;nix flake metadata --json | jq .dirtyRevisionnull);nix build .#felis && ./result/bin/felis --versionprintsfelis 0.1.0 (<rev> )with no-dirtyand<rev>=git rev-parse HEAD.v0.1.0-rc.1(annotated) at the release commit;release.ymlgreen, prerelease created. Then delete the rc release/tag or leave it marked prerelease — decide and document in workspace.md.Tag and publish
git tag -a v0.1.0 -m "felis 0.1.0"on the gated commit;git push origin v0.1.0(never--force, perCLAUDE.md).release.ymlruns: verify-tag, build, smoke, niks3 push, Forgejo release with schema + proto + Linux store-path/narHash + CHANGELOG body.nix run 'git+https://git.natsukium.com/natsukium/felis?ref=refs/tags/v0.1.0' -- --versionon a machine with the cache configured substitutes (no compile) and reports the tag identity;felis version --format json(#17) against a daemon started from that build shows all three identities equal; the docs package (.#docs) built from the tag, if a version stamp was added, matches.Tests that prove it
Release is proven by the CI runs and the post-checks above; the only code-level test this issue adds is the
package.nixversion-source change being covered byjust release-check'snix evalcomparison and bychecks.home-manager-module(flake.nix, evaluates the package).Dependencies
Everything in #12's P0/P1 list plus #42/#53/#54 (#53/#54 are already landed at
5a1a49a2; #42 is open). Direct blockers for this issue's own steps: #17 (identity to compare), #18 (tag workflow +just release-check), #19 (the compatibility gate the acceptance criteria name), #30 (the wire baseline must be final before the tag freezes it — "after every other wire edit" in the tracker order), #29 (golden schemas/conversations frozen at the tag). The tracker's recommended order still holds; #31 is last.Risk/effort
S for the commit itself; M for the sweep, since it is the one moment every hand-maintained mirror (CHANGELOG, skill, install docs, support matrix) has to agree and no test covers prose. Main risk: tagging a commit whose
mainrun was green but whose docs still say "eachmainrevision" or whose skill lists a verb #23 renamed — the grep list above is the mitigation. Secondary: theversion.workspace = truemigration changingnix/package.nix's version lookup; do it as its own commit and letpr.yml'slinux-smoke(nix build .#felis) prove it.Labels
Keep
priority/P0,release/v0.1.0. Edit the scope line "Set the inherited workspace version" to "Move crate versions toversion.workspace = true, then set the workspace version", and add acceptance items: "rc-tag rehearsal run recorded" and "post-publishnix run …?ref=refs/tags/v0.1.0 -- --versionsubstitutes from the cache and reports the tag identity".Review amendments (round 2)
felis version --format json.cli.revision(full) withgit rev-parse HEADand.cli.dirty == false;felis --versionis a human smoke line and is not compared.Review amendments (round 3)
just check, generated-proto and schema sync,proto-compat, build, and smoke on the exact tag SHA; #31 does not rely on the earliermainrun. The first-tag compatibility base is the committedfirst-releaseacknowledgment, removed in the first post-tag commit.Release preparation (2026-09-08)
Everything up to the tag is landed. No tag has been created or pushed — the tag push and the release workflow are the remaining manual steps, listed at the bottom.
What landed
workspace: single-source the crate version49af3c8arelease: cut v0.1.083b959e5The gated revision is
83b959e57a5bd1c689665a80ebec168423877e52(main).CI on each PR head, all required contexts green (Forgejo exposes them as job URLs, not run-level ones):
2db46cc9): runs/natsukium/felis/actions/runs/2567(bench),2568(darwin),2569(fuzz),2570(pr),2571(windows). Every contextsuccess;pr / publish felis,bench / full-suite,fuzz / nightly long-runand the two docs-only no-opsskipped, as they are on any PR.83b959e5): runs/natsukium/felis/actions/runs/2583(darwin),2584(pr),2585(windows). The change is docs-only, so the docs-only gate satisfied the Windows and darwin build contexts through their no-op jobs;pr / nix flake check,pr / cargo build / clippy / test / deny,pr / wire schema is compatible with the baseandpr / frontend smoke (x86_64-linux)all ran and aresuccess.Release commit checklist (plan items 1-7)
closed. Every remaining open issue in the repo ispriority/P2; only #12 and #31 remain from this tracker.just schemaandjust protoproduce no diff on the release commit.## [Unreleased]became## [0.1.0] - 2026-09-08, a fresh empty## [Unreleased]opens above it, the intro's "until a first release is tagged" sentence now states the released rule, and both link footers are in place.Unreleased,first release,first tag,compatibility freeze,each \main` revision, and unpinnedgit+https://git.natsukium.com/natsukium/felisrefs, acrossdocs/,README.md,CHANGELOG.md,CONTRIBUTING.md,skills/,scripts/,nix/,.forgejo/`. See "Where HEAD differs from the plan" below for what was changed and what was deliberately left.skills/felis/SKILL.md. Checked against the built binary: every verb the skill names exists, and its point/stream split matches the binary's--formatpossible values verb by verb (list/info/spawn/send/kill/evict/tag/daemon status/daemon stop/config check/doctor/version/window retargettakejson;capture/search/notifications subscribetakejsonl). Its one pre-release sentence was updated.x86_64-linuxonly, consistent acrossREADME.md("Four targets are on the roadmap…x86_64-linuxhas a passed runtime gate"),docs/reference/workspace.md"Build and platform matrix" and "Release gate", anddocs/how-to/install.md("The Windows deliverable" keeps Windows at CI evidence).0.1.0needed no bump; the pre-step made it one line for next time.Gates on the exact merged revision
Run in a clean detached checkout of
83b959e5(git status --porcelainempty,nix flake metadatareportsdirtyRevision: null):.cli.revisionequalsgit rev-parse HEADand.cli.dirtyisfalse.just checkandjust prose-checkpassed on the commit before it was pushed.Where HEAD differs from the plan (2026-09-03)
The plan was written against
69076d42; these are the points where the tree has moved on and HEAD won.PROTOCOL_MAJOR.nix/package.nix,scripts/release/verify.shread every crate's[package] version(the file did not exist when the plan was written), andscripts/make-macos-app.shreadfelis-cli's. Both now read[workspace.package] version; the gate's per-crate loop became an inheritance check, with a new self-test case for a crate that pins a version of its own.tests/was migrated with the eleven crates so no member is left pinned.just release-checkalready exists, so the plan's "add anix evalcomparison to it" was not needed as a new recipe;checks.home-manager-moduleandnix build .#felisboth evaluated the changed lookup before the pre-step merged.docs/how-to/update-felis.mdno longer carries the "first tagged release" sentence the plan names at:99; #25's rewrite replaced that section.docs/how-to/install.mdalready documents the pinned form in its own "Installing a specific release" section (?ref=refs/tags/v0.1.0), which #18 added. The quick-start refs inREADME.mdandinstall.mdwere left unpinned on purpose: the workspace matrix already says the tag build is the supported artifact and amainbuild is a preview of the next one, and pinning the quick start would put a version number in two more files at every release. Say so if you want them pinned instead.docs/reference/ipc.md,docs/reference/workspace.md"Versioning" anddocs/explanation/architecture/ipc.mdstill describe the freeze in the future tense, andcrates/felis-protocol/proto/BREAKING.mdstill carries thefirst-releaseacknowledgment. Per the round-3 amendment that acknowledgment is the compatibility base this tag is checked against and is retired in the first commit after the tag; the wording flips with it, in that commit, not this one. Only the CLI epoch's rename rule was flipped now, becausedocs/reference/cli.mdalready stated it unconditionally and the shipped skill contradicted it.release.ymlbuilds a candidate's body from## [Unreleased], which the release commit just emptied. That is cosmetic —verify.shdoes not ask a candidate for a CHANGELOG section — but do not read the empty body as a failed rehearsal.Remaining manual steps
Run from a clean checkout of
83b959e5.1. Rehearse with a release candidate.
Then watch
release.yml(Actions →release):verify-tag, the reruns,linux-publish, and a prerelease release page forv0.1.0-rc.1carryingfelis-x86_64-linux.txt,felis-config.schema.json, andfelis.proto. Record the run URL here.2. Cut the release tag on the same commit, once the rehearsal is green.
release.ymlruns the whole gate on the tag's own revision and publishes the release page (draft → assets → published).3. Post-publish checks, on a machine that has the cache configured as a substituter:
It must substitute rather than compile, and report
"version":"0.1.0","revision":"83b959e57a5bd1c689665a80ebec168423877e52","dirty":false— the same identityfelis-x86_64-linux.txton the release page names. Compare the attachedfelis.protoandfelis-config.schema.jsonwith the tag's own copies.4. Afterwards: retire the
first-releaseacknowledgment incrates/felis-protocol/proto/BREAKING.mdagainst the published baseline and flip the proto-surface wording with it (the round-3 amendment's post-tag commit), decide whether the rc release page stays or is deleted and record that inworkspace.md, then close #31 and #12 with the run URLs.