0.6.93 built five clean binaries, asserted every architecture was present, and
published nothing. The publish job died at "Verify release notes header matches
version" with `actual: <none>`, and every step after it — the GitHub Release and
both npm publishes — was skipped.
The cause is two release-notes generators writing to two directories, only one
of which anyone reads.
The `release-notes` job does the right thing: it writes
docs/release-notes/RELEASE_NOTES.md, headed `## @hanzo/dev v<version>`, and
uploads it as the release-metadata artifact. The `release` job then downloads
that artifact, checks it is non-empty — and never copies it into place. It
scratch-generates into a second, root-level release-notes/ instead. So the
verifier read the copy committed in the tree, which was still headed
`## @just-every/code v0.6.169` from before the fork was rebranded. No line
matched `^## @hanzo/dev v`, hence `<none>`.
Three fixes, smallest first:
- "Apply generated release metadata" now applies it — copies CHANGELOG.md and
RELEASE_NOTES.md from the artifact into the tree, which is what the step name
has always claimed.
- The release-notes fallback asked the wrong question. It was gated on
`env.OPENAI_API_KEY == ''`, but the generator it backs up runs our own `dev`
binary, and `dev` defaults to the hanzo provider — it needs HANZO_USER_KEY.
Set the OpenAI secret without the Hanzo one and the agent dies with "Missing
environment variable: HANZO_USER_KEY", the `||` swallows it, and the fallback
is skipped because the OpenAI key is non-empty. It now keys off the artifact:
write deterministic notes whenever they are missing or wrongly headed.
Publishing must not depend on a model call succeeding.
- The stale committed RELEASE_NOTES.md carried the upstream fork's brand into
our own release page. Reset to this version.
Also stopped committing the scratch directory. Only docs/release-notes/*.md
were ignored, so the root generator's context.md and prompt.expanded.txt were
not, and each release added ~650 KB of expanded prompt to the repo. The new
ignore is anchored (`/release-notes/`) because a bare pattern would also swallow
the tracked docs/release-notes/.
Our history is just-every's with author emails rewritten, so the graphs are
disjoint and git finds no merge base. Supplied one by hand: d1f1f51a41, the
just-every commit matching our Oct-2025 fork point (22 files apart). 9618
upstream commits, 7004 files, +1.81M/-159k, 37 conflicts.
Resolution:
- Upstream code where our side was the Oct-2025 prototype of a feature they
have since reimplemented 3-5x larger (agent_runs, browser_sessions,
history_cell/{agent,browser}, the vt100 harness and its snapshots).
- Upstream's config.rs module split (builder/defaults/sources/validation)
kept; zen5-coder and the provider-follows-model rule re-applied on top.
- Ours where the file IS the identity: README, package.json, postinstall,
release notes pipeline, integration-zed.
- Hybrid where upstream improved a file we had branded: updates.rs (their
release-repo migration, our hanzoai/dev), release.yml (their fail-fast npm
auth check, our package name), chatwidget.rs (their turn handling, our
HANZO_USER_KEY hint), exec human output (their 237 lines, our banner).
Superseded and dropped deliberately: our resume_command_name() coder-alias
hack — upstream's derive_resume_command_name() reads the invocation basename
generically, which yields "dev" for us.
LLM.md now records the real topology and the sync point; AGENTS.md and
CLAUDE.md are symlinks to it again. Single parent on purpose: adopting
jecode/main as a second parent would re-import 13,742 commits carrying the
upstream author emails a prior rewrite deliberately removed.
Version 0.2.188 -> 0.2.189.
Co-authored-by: Hanzo Dev <[email protected]>