Skip to content

Cycle for Zcode 1.0.7

Pre-release
Pre-release

Choose a tag to compare

@jannotix jannotix released this 19 Sep 16:19
· 32 commits to main since this release

Important

Superseded by 1.0.8 before this release was ever certified. Install 1.0.8 instead.

The certification host moved while this release was being set up for its live
campaign: the bundled ZCode CLI went from 0.16.5 to 0.16.9. That version is
named in the threat model this archive ships, where it conditions a trust
boundary, so these bytes describe a host configuration that no longer exists —
and a receipt earned on the new host would be rejected by the release lane's own
verifier, which asserts the CLI version a campaign ran on.

1.0.8 carries these seven fixes unchanged and names the host that will certify
them. No product code differs between the two.

Cycle for Zcode 1.0.7

Governed delivery for ZCode: an architect plans, an executor implements inside an
isolated worktree, two independent reviewers judge the frozen candidate, and an
arbiter decides — with every gate result and verdict written to a hash-chained,
signature-checkpointed ledger.

This release closes seven defects. Six were found by running the thirteen-scenario
live campaign against the published 1.0.6 archive — downloaded, checksum-verified
and checked against its provenance attestation — on Windows and in WSL. Eleven
scenarios passed; the two that failed are the first two below. The seventh was found
in the release machinery while shipping this one.

Fixed

A per-role model assignment is usable, not merely configurable. /cycle:models
accepted exactly three model references, all under one provider prefix, and reported
them as applied with no warning. All three failed at dispatch with
provider-not-found — on the provider prefix, not the model name — because the
host resolves providers under a namespace the plugin refused to accept. The only
setting that worked was inherit, which is the absence of the feature the product is
named for, and the failure surfaced at the review phase, after an architecture, an
execution and five verification gates had been paid for. A plugin cannot enumerate a
host's providers and has no business deciding which ones exist: Cycle now validates
the shape of a reference and leaves resolution to ZCode. What it owes the operator
instead is an early answer, so a pinned role is reported as dispatch_unverified and
the run protocol probes every pin before a workflow starts. An unresolvable provider
now costs seconds.

Every receipt written by 1.0.6 and earlier therefore records a run in which architect,
executor, both reviewers and the arbiter shared one model — independent prompts and
tool lists, one judgement. Those receipts do not imply the wider claim.

An abrupt stop no longer leaves a workflow unrecoverable and the project locked.
Recovery required a worktree to exist on disk if and only if a base revision had been
recorded. A session killed between those two writes broke the invariant, and recovery
refused outright. Refusing was wrong twice over: recovery only reads — the guards that
matter live on prepare_worktree and freeze, and they still hold — and the refusal
returned before the immutable request text was assembled, withholding the one thing an
interrupted operator cannot reconstruct exactly when it was needed. Meanwhile the
mutation lock kept the project read-only, including for an unrelated delivery already
sitting uncommitted. Recovery now names the inconsistency, returns a recovery action,
and hands back everything it knows.

One project directory can no longer carry two identities. project_key was
whatever the calling agent chose to pass, and the run protocol only described it as
"this workspace's stable project key". It was neither. The server now derives it
canonically from the directory and ignores what the caller sends.

/cycle:setup install no longer deadlocks the first governed run. It left managed
role profiles visible to git, so the first freeze saw a dirty tree it had itself
created. They are excluded now, and the report says so rather than leaving the
operator to discover it.

Risk routing sees the code a change touches. No path could raise Authentication,
Authorization, Cryptography or Secrets: only the request text could, and only by
literal marker. A change to auth.js therefore routed to quick — no independent
reviews — unless the author happened to write "authentication" in their request. The
campaign demonstrated exactly that, twice, on the same fixture. Paths now raise a
category on their own, matched as whole tokens so auth.js counts and authors.md
does not, with documentation taking precedence over everything else.

The uninstall documentation named the wrong directory. It said ZCode keeps the
marketplace's cached copy of the plugin. That cache is emptied completely. What
remains is ZCode's mirror of the marketplace source under
plugins/marketplaces/<marketplace>/, and it is larger than the installation was,
because it carries every platform's daemon rather than only yours. Someone following
the old wording would check the plugin cache, find it empty, and conclude the removal
was complete.

Fixed in the release machinery

The daemon version gate no longer passes the daemons it exists to reject.
Assembling this release copied the 1.0.5 daemons into the plugin and wrote a
manifest declaring them 1.0.7. They had been sitting in the untracked staging
directory since that release — nothing clears it — and the gate reported no problem.

That gate had already failed once on these same two files. Until 1.0.6 it scanned the
executable for the expected version as a substring, and in a 39 MB binary the sequence
turns up on its own, so the 1.0.5 Linux daemon was read as declaring 1.0.6. It was
rewritten to execute workflowd --version. But --version was added in 1.0.6, so
the one daemon that cannot answer is one older than the flag — precisely the case the
gate is for — and not answering was recorded as the same unverified state used for a
daemon built for another platform, which is a legitimate skip. Both callers blocked
only on a daemon that answered and answered wrong. The daemon that would not speak
walked past both.

What shipped as 1.0.6 is unaffected: the release workflow builds both daemons from
source on their own platforms before assembling, so the published archive carries
genuine binaries. The defect was in what a local assembly stages and what the merge
gate would have allowed into the repository — and since the native manifest takes its
product version from the plugin manifest rather than from the binary, the result
carried an honest digest beside a version nobody had read.

A result now records whether the machine could execute the file at all. Runnable and
silent is a failure; not runnable here is a skip, left to the CI job that can run it.
Assembly additionally refuses when a staged daemon is missing outright, because that
copy used to throw after the previous plugin directory had been removed.

Known ZCode limitations

Uninstalling the plugin empties its cache but leaves ZCode's mirror of the marketplace
source — roughly 76 MB, including a native daemon for every platform rather than only
yours — in your ZCode profile. This is host behaviour: the mirror and its registry
belong to ZCode, and a plugin reaching in to erase entries would be a worse fault than
the disk space it recovers. The retained copy is inert. Remove the marketplace itself
to reclaim the space. Your audit data is untouched by an uninstall, which is why the
control plane lives outside the plugin tree.

The Windows daemon is unsigned; authenticode.json records NotSigned. That is a
declared limitation of this release, not a failure, and the clean-install job verifies
it is unsigned rather than badly signed.

Schema

Unchanged at schema 18. A newer schema opens in the documented safe read-only mode
rather than refusing or migrating downward.

Verification

Rust 304 tests, MCP 46, qualification 24, clippy and cargo fmt clean. Built, sealed,
clean-installed on Ubuntu 22.04, Ubuntu 24.04 and Windows 11, and attested with build
provenance by release-candidate run 35453712382 from 4dbab330c00ac05ffee68d2e221dc4201042d4fb — the commit this tag names.

artifact SHA-256
zcode-cycle-1.0.7.zip 2f2d1b79859452de81b391584a11f3aea2f1c0d525159d11f5df73de0b089a32
zcode-cycle-native-linux-x64-1.0.7.tgz 56027ee21f3f3c57ffb5f32181fe423b89c3f1d2f57a4884ff3efb534446c9f8
zcode-cycle-native-win32-x64-1.0.7.tgz 0eafc541a9362dbf1d6f140768094d6e5169945bb81af72379d1b293d850dbf1

Both native archives are byte-identical to the ones produced by an earlier seal of
a different commit, so the daemon builds reproduce across runs. The plugin ZIP
differs in exactly two of its seventy-one entries - provenance.intoto.json and
SBOM.cdx.json, the only files that name the commit they were built from. Every
other entry matches byte for byte.

Not yet claimed

This build has not been through the thirteen-scenario live campaign. Every fix
above is covered by tests and the whole release lane is green, but the live campaign
is what found six of the seven defects this release closes — in a 1.0.6 that was also
entirely green, and that had itself been sealed and attested. Until 1.0.7 has been
certified live against these exact bytes, this is a sealed and reproducible candidate
rather than a certified release, and it is marked as a pre-release for that reason.