Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions artifacts/CHALLENGE_DETAILS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Committed agent-rename recovery

Upstream report: [zeroclaw-labs/zeroclaw#10373](https://github.com/zeroclaw-labs/zeroclaw/issues/10373).

Original issue pin: `c1e79a774b8d0a8539481b08838a3c818c97a6d0`.

Branch base: `fb116d612` (`origin/master`), one commit after that pin. Both patches still apply on this base.

## Contract

One runtime-owned recovery record is shared by the CLI, the gateway map-key handlers, and RPC. It is armed when a rename commits (and when a committed rename is discovered with residue or an unreadable follower). It is cleared only after workspace, memory, cron, ACP, and session followers have been read and converged. While it is open, the retired alias cannot be created again, including after residue is deleted out of band.

Knowledge-graph ownership from unmerged work is out of scope. Followers are the ones on this pin: default per-alias workspace, memory, cron, ACP sessions, and session attribution.

## Why a naive patch fails

Copying the existing gateway residue scan into the CLI is not enough:

- That scan fails open. An unreadable cron database is treated as "no residue", so the rename is reported as not configured and recovery is not armed. The tests require a retryable failure and a refused recreate of the old alias.
- Residue alone cannot tell a stranded rename from an alias that was recreated on purpose. After an out-of-band wipe, a residue scan allows `agents create` of the retired alias. The tests require that create to keep failing until a later rename converges and clears recovery.
- A gateway-only journal is invisible to the CLI, and a CLI-only journal is invisible to the gateway. The cross-surface test arms recovery through the gateway handler and then requires the CLI to refuse the old alias and later finish the same recovery.
- Clearing recovery on the first follower error, or moving a custom workspace path, fails the blocked-workspace and custom-workspace cases.
- HTTP and RPC still return a committed rename when a follower lags, matching the existing gateway tests. The CLI must exit non-zero for that same lag, without the "is not configured" wording.

The hidden tests call the `zeroclaw` binary, the public gateway handlers, and the public RPC dispatcher. They do not import the recovery module, so a solution that only adds an unwired helper still fails.

## Patches

`solution.patch` changes 7 production files:

- `crates/zeroclaw-runtime/src/agent_rename_recovery.rs`
- `crates/zeroclaw-runtime/src/lib.rs`
- `crates/zeroclaw-runtime/src/rpc/dispatch.rs`
- `crates/zeroclaw-runtime/locales/en/cli.ftl`
- `crates/zeroclaw-gateway/src/api_config.rs`
- `crates/zeroclaw-gateway/src/agent_owned_state.rs`
- `src/alias_cli/mod.rs`

`test.patch` changes 5 files and does not overlap those paths:

- `Cargo.toml`
- `test.sh`
- `tests/committed_agent_rename.rs`
- `crates/zeroclaw-gateway/src/lib.rs`
- `crates/zeroclaw-gateway/src/committed_rename_recovery_tests.rs`

## Harness

`test.sh --output_path FILE {base|new}` runs, without `set -e`:

- `cargo test --offline --test committed_agent_rename -- --test-threads=1`
- `cargo test --offline -p zeroclaw-gateway --lib committed_rename -- --test-threads=1`

It writes JUnit from the cargo `test ... ok|FAILED` lines. Exit status is non-zero when any cargo invocation fails. `base` (tests only) is expected to be non-zero. `new` (tests plus solution) is expected to be zero.

Build the image with the repository root as context after `test.patch` is applied and before `solution.patch`:

```sh
docker build -f artifacts/Dockerfile .
```

The image is `rust:1.96-bookworm`, `WORKDIR /app`, fetches the locked crates, compiles the harness tests with `--offline --no-run`, and ends with `CMD ["bash"]`.
15 changes: 15 additions & 0 deletions artifacts/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM rust:1.96-bookworm

RUN apt-get update \
&& apt-get install -y --no-install-recommends pkg-config libssl-dev \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY . .

RUN cargo fetch --locked \
&& cargo test --offline --no-run --test committed_agent_rename \
&& cargo test --offline --no-run -p zeroclaw-gateway --lib

CMD ["bash"]
71 changes: 71 additions & 0 deletions artifacts/VERIFY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Harness verification

Original issue pin: `c1e79a774b8d0a8539481b08838a3c818c97a6d0`.

Resynced onto `origin/master` at `fb116d612` (`feat(log): add entry-count rotation and multi-segment log queries (#10214)`). That commit edits `crates/zeroclaw-runtime/src/rpc/dispatch.rs` only around the log-query handlers, not the rename handlers. On this base:

```sh
git apply --check artifacts/test.patch
git apply --check artifacts/solution.patch
```

Both succeeded. The fail-to-pass runs below were executed on the original pin before this rebase.

Path intersection of `solution.patch` and `test.patch` is empty.

Solution files (7):

- `crates/zeroclaw-runtime/src/agent_rename_recovery.rs`
- `crates/zeroclaw-runtime/src/lib.rs`
- `crates/zeroclaw-runtime/src/rpc/dispatch.rs`
- `crates/zeroclaw-runtime/locales/en/cli.ftl`
- `crates/zeroclaw-gateway/src/api_config.rs`
- `crates/zeroclaw-gateway/src/agent_owned_state.rs`
- `src/alias_cli/mod.rs`

Test files (5):

- `Cargo.toml`
- `test.sh`
- `tests/committed_agent_rename.rs`
- `crates/zeroclaw-gateway/src/lib.rs`
- `crates/zeroclaw-gateway/src/committed_rename_recovery_tests.rs`

## Commands

Tests only (solution reverted, `test.patch` contents present):

```sh
./test.sh --output_path /tmp/junit-base.xml base
```

Exit code: `1`. JUnit: `tests="12" failures="12"`. Every CLI, gateway, and RPC case failed its assertion. Representative base results:

- CLI resume of a committed rename reported `invalid new alias: alias agent_b already exists` instead of converging followers.
- CLI create after an unreadable cron store printed `created agents.agent_a`.
- Gateway create after an unreadable cron store returned `{"created":true,...}`.
- An unrelated `agent_a -> agent_b` with no residue returned HTTP 400 `alias agent_b already exists` rather than 404 `is not configured`.

Tests plus solution (`git apply artifacts/solution.patch`):

```sh
./test.sh --output_path /tmp/junit-new.xml new
```

Exit code: `0`. JUnit: `tests="12" failures="0"`.

`base` is non-zero. `new` is zero.

## Other checks

```sh
cargo fmt -- --check <changed Rust files>
cargo clippy -p zeroclaw-runtime --lib -- -D warnings
cargo clippy -p zeroclaw-gateway --lib --tests --no-deps -- -D warnings
cargo clippy --bin zeroclaw --test committed_agent_rename --no-deps -- -D warnings
bash -n test.sh
```

All exited 0. A workspace-wide `cargo clippy -p zeroclaw-gateway --lib --tests -- -D warnings` stopped in pre-existing `zeroclaw-channels` `clippy::drop_non_drop` findings and did not report diagnostics in the recovery files.

`docker build` was not run. The image recipe is `artifacts/Dockerfile` (`rust:1.96-bookworm`, `WORKDIR /app`, `cargo fetch --locked`, offline `--no-run` for `--test committed_agent_rename` and `-p zeroclaw-gateway --lib`, `CMD ["bash"]`). The fail-to-pass commands above are the ones that image is meant to run.
Loading
Loading