Cycle for Zcode 1.0.8
Pre-releaseImportant
Superseded by 1.0.9. Install 1.0.9 instead.
The threat model this archive ships states that ZCode CLI 0.16.9 does not
execute plugin-provided agent components. That was checked by direct
observation on Desktop 3.14.1.7714, and it is false: the host reads the
agents/ directory this archive contains and lists all five roles as
dispatchable subagents.
It is a documentation defect rather than a hole - the definitions the host
reads are the managed role profiles themselves, with the same bounded tool
lists, and the built-in general-purpose subagent already holds every tool.
But an archive should not carry a security statement its own certification
refuted, which is the whole reason 1.0.9 exists. No product code differs
between the two.
Cycle for Zcode 1.0.8
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.
1.0.8 changes no product code. It carries the same seven fixes as 1.0.7 and
exists because the certification host moved while 1.0.7 was being set up for its
live campaign. Install this instead of 1.0.7.
ZCode Desktop went from 3.12.3.7463 to 3.14.0.7681 — the update had already been
downloaded and was waiting for a restart, and three of the thirteen live scenarios
require one, so the campaign could never have finished on the build it started on.
With that update the bundled ZCode CLI moved from 0.16.5 to 0.16.9, the first time
it has moved across four Desktop builds.
That second number is not bookkeeping. The shipped threat model conditions a trust
boundary on it — that the host does not execute plugin-provided agent components,
which is why /cycle:setup install writes five managed profiles explicitly rather
than relying on the host to discover the agents/ directory this archive contains.
1.0.7 was already published naming 0.16.5, so its archive described
a host configuration that no longer exists, and its receipt would have been rejected
by the release lane's own verifier, which asserts the CLI version a campaign ran on.
The seven fixes below are unchanged and were all found the same way: by running the
thirteen-scenario live campaign against 1.0.6's published 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. The seventh was
found in the release machinery while shipping them.
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.8. 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 35459373078 from
0f21c8fa8491cdc6ee1ac519f28a3a487c6aaeec — the commit this tag names.
| artifact | SHA-256 |
|---|---|
zcode-cycle-1.0.8.zip |
2b91c504a732727eb2488c81d93b6d40dcaa0233012ae113c26e2757910a9735 |
zcode-cycle-native-linux-x64-1.0.8.tgz |
8d4bd661d9d27142403e00499443b3171b32e3e2a808b092f1cf83c3f6b7e0c2 |
zcode-cycle-native-win32-x64-1.0.8.tgz |
ff412f16baa54ddbd888c7f038c9f8ba0dff2a003bf6f57244c44487b84a19e5 |
Both native archives are byte-identical to the ones an earlier seal of a different
commit produced, so the daemon builds reproduce across runs.
The dependency audit blocked this release for twenty-four minutes: the advisory
service returned HTTP 503 and three consecutive runs failed on it. The step was left
alone. An audit that cannot reach the database must not report a clean result, and
weakening it would have reproduced the defect the last section below describes.
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.8 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.