Skip to content

io-cli 0.34.1 - #89

Merged
aakashpawar1999 merged 7 commits into
mainfrom
develop
Sep 1, 2026
Merged

aakashpawar1999 merged 7 commits into
mainfrom
develop

Conversation

@aakashpawar1999

Copy link
Copy Markdown
Contributor

Release PR for 0.34.1. Everything in it came through #88; git diff --quiet feat/0.34.1 develop
is clean, so this is the tree the gates ran on.

A patch about honesty. Four published claims were wrong and no test decided any of them; one was a
real defect a script hits silently.

  • A usage error exits 1, not 2. clap's usage code is 2, which is REFUSED — so every
    mistyped flag told a CI job the boundary had stopped the run. Behaviour change, named in the
    CHANGELOG under Upgrading and scoped to every io command, not just io exec.
  • install.ps1 stops writing the user PATH, so the README's "neither edits anything" is true on
    Windows too. Nothing is un-written; the narration says what a profile line does not reach.
  • Exit 4 and the headless-refusal sentence carry their carve-outs, both bound to the functions
    they describe rather than to themselves.

Verification on this tree: cargo test --all-targets exit 0 over 102 binaries / 1,831 passed / 0
failed / 37 ignored
; doctest, fmt --check and clippy --all-targets -- -D warnings all exit 0;
live suite 36/37 with the one failure a model flake that passes alone; eight sabotage arms, seven
killing exactly their target and the eighth killing nothing, which was itself the finding; two
adversarial reviewers, one High fixed before the seal. All eight checks green on #88 across Linux,
macOS and Windows.

Record sealed and pinned before this merge: sha256:7ff1d44fea4c3da0bbf768fabc530c87f98a22d5aa574415f6cda4771050f987,
ultraship validate exit 0 over 108 checks.

Two defects found during the release are deferred to 0.35.0 with roadmap entries rather than
changelog mentions: a boundary refusal on the provider endpoint exits 1 instead of 2, and the
migration report is dropped when the first-run wizard is cancelled.

`Cli::parse()` exits with clap's usage code of 2, which is what
`exec::REFUSED` has meant since 0.5.0 — so every mistyped flag told a
script that a boundary had said no, at the one surface `docs/CONTRACT.md`
publishes to be branched on, while io-cli's own argument refusals already
exited 1. clap 4 publishes no `error_exit_code` builder knob, so the exit
is taken from `Cli::try_parse`: anything clap writes to stderr is a usage
error and exits FAILED, and `--help`/`--version` keep their 0.

Asserted through the real argv door, because the decision lives in
`src/main.rs` and nothing under `tests/` links it. The documented exit-code
table is now read as data and held against the constants row by row, with a
pairwise distinctness check, so the fix cannot trade one collision for a
neighbour without a test naming which row moved.
The README said neither installer edits anything and `install.ps1` called
`SetEnvironmentVariable('Path', ..., 'User')`. A user PATH write is not a
shell profile, but it is still an unasked-for change to the machine that
outlives the install, and `install.sh` has always printed the line instead.
The installer prints it too now. The user PATH is still read, because which
of the two messages is the true one depends on it; nothing is un-written,
so an install that already added the directory keeps that entry.

A drift test binds the pair: it fails if either script calls
SetEnvironmentVariable or setx while the README paragraph claims neither
edits anything, and asserts the GetEnvironmentVariable spelling is still
there so the forbidden needle is proven to be the API the file really uses.
Exit `4` was documented as naming the id "that `io resume` needs". It does
for three of the four pauses; an approval names its `request_id` and says
it is answered at the terminal instead, because io-harness publishes no
resume entry point that takes one — so a script written from the old
sentence went looking for a command that does not exist.

"Every approval in a headless run is declined, and the refusal is fed back
to the agent as an observation it can adapt to" is true of every approval a
tool call raises and false of one. The provider's own endpoint is
authorized before the run's first step, so an `ask` verdict there ends the
run with no turn to tell and nothing to adapt — and that refusal exits 1
rather than the 2 the table gives a boundary, because the typed error is
flattened to a message before a code is chosen. Recorded as a known defect
rather than left for a reader to discover.

Both drift tests bind the prose to the code: `exec::parked` is asked what it
prints for each pause, and `asks_nobody_can_answer` is asked whether it
reads the `net` tier at all. Neither page can be made true by editing it.
The CHANGELOG names the exit-code change under Changed and again under
Upgrading, because a script may be reading the old value: 2 no longer means
"refused or a usage error", and a usage error is 1. The Windows PATH change
gets the same treatment, and the boundary refusal that still exits 1 is
carried as a known limitation with 0.35.0 named as its destination.

Nothing in this workspace checks Cargo.toml's version, so the bump is the
step that keeps the shipped binary's --version from contradicting its own
release record.
Found by running its sabotage arm and getting nothing. Asserted over the
documented table, pairwise distinctness had no reachable arm: the length
check and the per-row check between them make a duplicate documented code
impossible to produce, because whichever row you move, one of those two
fires first.

Over the constants it has one, and it is the exact regression this release
removes — define two codes as the same number, document them both that way
honestly, and every other assertion in the test passes while a script loses
the ability to tell two endings apart.
Found by adversarial review. Removing the write left the branch reading
[Environment]::GetEnvironmentVariable('Path','User') while the advice it
prints is a PowerShell profile line, which never touches that registry
value — so an operator who did exactly as they were told would be told to
do it again on every update, forever, and the "already on your PATH"
branch would be unreachable for everyone who complied. $env:Path is what
the advice changes and what machine, user and session entries resolve
into; install.sh reads $PATH for the same reason.

The narration now also says what a profile line does not reach — cmd.exe,
Explorer and GUI programs — because the write it replaces was visible to
all of them. That is a reduction in reach, not only the removal of a
write, and the CHANGELOG says so.

The header's "nothing written outside that directory" was false against
its own file: the script stages the download in a temp directory. It now
says so.

Three test corrections, all of them gates that were not gating:
- the drift test's README needle was a PREFIX of the pre-0.34.1 sentence,
  so the one fragment this release added to the README was the one
  fragment the guard could not see. It is the whole clause now.
- it asserted the installer still READ the user PATH, which pinned a
  spelling nothing depends on any more. It now asserts both scripts still
  PRINT the line, which is the half of the README's promise an absence
  check cannot cover.
- n8's `'User'` needle went the same way; `!contains("'Machine'")` is the
  half that is still a permission claim.

docs/CONTRACT.md published `2` for every refusal while the headless guide
admitted one exits `1` — the contradiction sitting on the page headed "the
contract a CI job depends on". Both pages say it now, and a test asserts
the pair. The exit-`4` carve-out gained the fact that io produces that
pause nowhere at all, declining every approval rather than deferring one,
and `exec::parked`'s own doc summary carried the unqualified sentence this
release removed from two pages — a third copy, which is this repository's
recurring failure.
@aakashpawar1999
aakashpawar1999 merged commit 2bf5bed into main Sep 1, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant