Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
777ac66
feat: classify terminal Run Worktrees with positive proof
marcioaltoe Jul 27, 2026
e5985b3
feat: apply stale-proof cleanup and migrate terminal reaping
marcioaltoe Jul 27, 2026
5e7c0bc
feat: reconcile Integration Pending with durable evidence
marcioaltoe Jul 27, 2026
0d56f42
feat: deliver the Reconcile Command and apply contract
marcioaltoe Jul 27, 2026
5a596b6
feat: surface retained terminal Run Worktrees in Runs List
marcioaltoe Jul 27, 2026
c443d76
docs: align reconciliation docs and glossary
marcioaltoe Jul 27, 2026
16da675
docs: align the protected Roundfix Skill pair
marcioaltoe Jul 27, 2026
01a16c8
docs: record digest authorization and dogfood findings for spec 0038
marcioaltoe Jul 27, 2026
af03b5f
fix: stop delivering the stray root build binary
marcioaltoe Jul 27, 2026
5334d6c
docs: qa report for 0038-terminal-run-worktree-reconciliation (fail)
marcioaltoe Jul 27, 2026
97fc282
docs: revert unauthorized ignore-file edit and record the gap
marcioaltoe Jul 27, 2026
3744d03
docs: restore .gitignore byte-for-byte and record the Go cache gap
marcioaltoe Jul 27, 2026
f1d9018
docs: qa report for 0038-terminal-run-worktree-reconciliation (pass)
marcioaltoe Jul 27, 2026
a6dd48f
docs: archive spec 0038-terminal-run-worktree-reconciliation
marcioaltoe Jul 27, 2026
44fa422
chore: include CodeRabbit nitpicks as Review Issues
marcioaltoe Jul 27, 2026
dcf87c7
fix: resolve Roundfix batch 001
marcioaltoe Jul 27, 2026
b9102d8
docs: review rounds for pr 39
marcioaltoe Jul 27, 2026
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
40 changes: 40 additions & 0 deletions .agents/skills/roundfix/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,46 @@ roundfix: warning: Journal Retention prune failed: <reason>

and never block the Run.

## Run Worktree reconciliation

Use the Reconcile Command to inspect retained terminal spec Run Worktrees and
Run Branches. Always run a dry-run before applying cleanup:

```bash
roundfix reconcile <run-id>
roundfix reconcile
roundfix reconcile <run-id> --format json
```

A Run ID selects one terminal spec Run; omitting it scans the current
repository. The report classifies every selected Run into one of five states:

| State | Agent action |
| --- | --- |
| `safe` | The Run Branch and recorded target resolve, any present registered Run Worktree is clean, and the Run Branch tip is an ancestor of the target tip. This is the only state eligible for cleanup. |
| `unintegrated` | Clean, resolved evidence proves that the Run Branch tip is not an ancestor of the target tip. Preserve the Run Worktree and Run Branch. |
| `dirty` | A present registered Run Worktree has tracked or untracked changes. Preserve the Run Worktree and Run Branch. |
| `unknown` | Metadata or Git evidence cannot prove another state. Preserve every identified Run Worktree and Run Branch. |
| `released` | Both the Run Worktree and Run Branch are absent. No cleanup is needed. |

After reviewing the dry-run, apply cleanup explicitly:

```bash
roundfix reconcile <run-id> --apply
roundfix reconcile --apply
```

`--apply` is the only mutation switch. Roundfix acts only on entries classified
`safe` during that invocation and rechecks their metadata, worktree
cleanliness, heads, and ancestry before mutation. It preserves `unintegrated`,
`dirty`, and `unknown` work, and treats `released` as an idempotent no-op.
There is no force bypass.

Never substitute manual Git deletion for this supported workflow. Do not run
`git worktree remove`, delete the Run Branch, or remove a recorded worktree
directory by hand. The Reconcile Command owns safety proof, evidence recording,
the guarded Integration Pending transition, and cleanup.

## Stopping Runs

Use `roundfix stop` for a graceful stop. Every selector keeps its existing
Expand Down
2 changes: 1 addition & 1 deletion .roundfixrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ profiles:

review_source:
name: coderabbit
include_nitpicks: false
include_nitpicks: true

watch:
until_clean: true
Expand Down
4 changes: 2 additions & 2 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ The named branch (`roundfix/run-<id>`) that carries a spec Run's commits inside
_Avoid_: Temp branch, detached HEAD, feature branch

**Run Worktree Reconciliation**:
The proof-based classification of a terminal spec Run's retained Run Worktree and Run Branch as `safe`, `unintegrated`, `dirty`, `unknown`, or `released`, followed by optional cleanup only for `safe` work.
The proof-based classification of a terminal spec Run's retained Git surfaces: `safe` when the Run Branch and recorded target resolve, any present Run Worktree is registered and clean, and the Run Branch tip is an ancestor of the target tip; `unintegrated` when the same evidence resolves but ancestry is false; `dirty` when a present Run Worktree has tracked or untracked changes; `unknown` when metadata or Git evidence cannot prove another state; and `released` only when both the Run Worktree and Run Branch are absent. Only `safe` work can be cleaned up, after the proof is rechecked.
_Avoid_: GC, force cleanup, manual branch deletion

**Integration Pending**:
Expand Down Expand Up @@ -339,7 +339,7 @@ The local recovery command that re-runs one failed Task's Verification commands
_Avoid_: Retry command, auto-settle, task fix command

**Reconcile Command**:
The support command that inspects terminal spec Run Worktrees and Run Branches, reports their Run Worktree Reconciliation state, and removes only `safe` work when explicitly invoked with `--apply`.
The support command that inspects terminal spec Run Worktrees and Run Branches and reports their Run Worktree Reconciliation state. It is read-only by default; `--apply` is its only mutation switch, removes only freshly revalidated `safe` work, and has no force bypass.
_Avoid_: GC Command, Settle Command, automatic integration

**Reprocess Command**:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
status: pending
created_at: 2026-07-27
updated_at: 2026-07-27
---

# Build hygiene — `go build ./cmd/roundfix` drops a 20 MiB binary at the repository root, and nothing ignores it (2026-07-27)

`.gitignore` ignores `/bin/`, which is where the Makefile writes its build
output. It does not ignore `/roundfix`, which is where `go build ./cmd/roundfix`
writes when invoked without `-o`. Agents run the bare form routinely as a
compile check, so the artifact appears unignored and untracked in a working tree
that Daemon commits stage by diff.

On 2026-07-27 that is exactly what happened: Spec 0038 Task 04's commit
`0d56f42` shipped a 20.1 MiB Mach-O arm64 executable at the repository root. The
Spec 0038 QA gate caught it as `RFQA-0038-01` and failed the gate. Neither
`make verify` nor CodeRabbit would have caught it — it is not a code error but a
scope-integrity problem, and only the QA gate's changed-path audit compares what
a Spec delivers against what it declared.

## Why the obvious fix needs authorization

Adding `/roundfix` to `.gitignore` closes the hole in one line. But
`docs/agents/agent-instructions.md:27` prohibits editing any "ignore file"
without express maintainer authorization, and no Spec's Tooling authority entry
covers `.gitignore`.

This finding records that boundary honestly: during the repair of
`RFQA-0038-01`, the supervisor removed the stray binary **and** added the ignore
entry. The next QA run flagged the ignore edit as an unauthorized protected
tooling mutation, and the entry was reverted, leaving only the binary removal —
which is all the QA finding actually required. The gate was right, and the
recurrence risk is still open.

## Suggested resolution

1. With maintainer authorization, add `/roundfix` to `.gitignore` with a comment
naming its source, so a bare build cannot be swept into a commit again.
2. Consider whether the Daemon's commit staging should refuse to stage
executable files outright. A build artifact is never legitimate Task output,
and a guard there protects every repository rather than this one path in this
one repository.
3. Consider making the bare `go build ./cmd/roundfix` unnecessary — a documented
compile-check target (`make build` already exists and writes to the ignored
path) that guides Agents away from the form that litters the tree.

## Suggested acceptance checks

- Running `go build ./cmd/roundfix` leaves no path that `git status` reports as
untracked.
- A Task commit that would include an executable file is refused or reported.
- The Spec 0038 QA scope audit passes on a rerun.

## What worked — keep

- The QA gate's scope-integrity audit is the only check that caught this, and it
caught it by comparing delivered paths against declared Spec scope. Keep that
step; it finds a class of defect the test suite and code review cannot.
- The gate also caught the supervisor's own over-reach on the repair commit,
which is the behavior you want from an authorization audit that is not
deferential to whoever is driving.
166 changes: 166 additions & 0 deletions docs/findings/2026-07-27-claude-adapter-standardization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
status: pending
created_at: 2026-07-27
updated_at: 2026-07-27
---

# Agent Selection — standardize on the official Claude adapter and stop reading `[...]` as reasoning effort (2026-07-27)

The maintainer directs Roundfix to drop every reference to
`@zed-industries/claude-code-acp` and support only
`@agentclientprotocol/claude-agent-acp`, including Doctor and Setup. This
finding records the empirical verification that the replacement works, the
exact code sites that still name the deprecated package, and one **new
blocking defect** that only becomes visible after the migration: Roundfix
misreads the replacement's advertised model identifiers.

This continues
[2026-07-26 — the configured Claude ACP adapter is deprecated](2026-07-26-claude-adapter-configoptions-migration.md),
which proposed the migration while `claude-agent-acp` was still uninstalled.
That finding's premise that `claude-opus-5` "is advertised and gets selected
successfully" describes the deprecated adapter only, and no longer holds — see
section 3.

No repository change was made: an Implement Run for Spec
`0038-terminal-run-worktree-reconciliation` was active, and editing tracked
files during a Run strands it in Integration Pending.

## Session evidence

- Repository `/Users/marcio/dev/roundfix` at `8ec92ad`, macOS 25.5.0.
- `acpx 0.12.1`. `codex-acp` resolves to `@agentclientprotocol/codex-acp@1.1.7`.
- `@agentclientprotocol/claude-agent-acp@0.63.0` installed globally during this
session; `~/.acpx/config.json` `agents.claude.command` repointed from
`claude-code-acp` to `claude-agent-acp`. Prior config backed up.
- Every proof below ran through
`roundfix profiles configure --scope project --file <fragment> --dry-run --json`,
which proves an exact tuple without writing config or creating a Run. From
inside a Claude Code session the probe needs
`env -u CLAUDECODE -u CLAUDE_CODE_ENTRYPOINT -u CLAUDE_CODE_SSE_PORT`.

## 1. The replacement adapter resolves the capability failure

With the deprecated adapter, every Claude tuple failed identically —
including `reasoning_effort: ""`, which rules out model and effort as causes:

```text
classification: capability_evidence_invalid
adapter error: capability evidence invalid: missing_config_options
```

With `@agentclientprotocol/claude-agent-acp@0.63.0`, the same probe reaches
model evaluation and reports the controls it advertises:

```text
advertised Agent Models: default, opus[1m], claude-fable-5[1m], sonnet, haiku
advertised reasoning efforts: default, low, medium, high, xhigh, max
```

`claude / sonnet / xhigh` proves clean. Claude is a usable runtime again, and
the migration is confirmed as the correct fix.

## 2. Roundfix reads `[...]` as reasoning effort, so `opus[1m]` is unselectable

`parseModelCapability` (`internal/agent/selection_capabilities.go:469`) treats
any advertised identifier shaped `name[suffix]` as Roundfix's model-variant
encoding `canonical[effort]`. The replacement adapter uses that bracket for
the **1M context window**, not for effort. The collision is proven:

| Requested selection | Result |
| --- | --- |
| `claude / opus[1m] / xhigh` | fails `model_not_advertised` — although `opus[1m]` is in the advertised list |
| `claude / opus / 1m` | **passes** — Roundfix parsed canonical `opus` + effort `1m` |
| `claude / sonnet / xhigh` | passes — no brackets, so the independent reasoning control is used |

Two consequences. A user cannot select a model by the identifier the adapter
actually advertises. And the only route to Opus today is to write a context
window into `reasoning_effort`, which forces the model-variant encoding and
therefore **discards explicit effort control** — the Task runs at the adapter's
default effort, not the configured one.

The adapter advertises an independent reasoning select *and* bracketed model
identifiers at the same time. That combination is what Roundfix does not model:
when an independent reasoning control exists, the model identifier must be
treated as opaque instead of being parsed for an embedded effort.

## 3. `claude-opus-5` is not advertised by the replacement adapter

The advertised set is `default, opus[1m], claude-fable-5[1m], sonnet, haiku`.
Both `.roundfixrc.yml` files that pin `frontend` — this repository's and
`fluxus`'s — request `claude / claude-opus-5 / xhigh`, which no adapter
lineage advertises. Those profiles stay broken after the migration until they
are repointed, so any Spec with a `frontend` Task is blocked in both
repositories. Repointing is a supervisor-owned boundary commit, not Run work.

## 4. Code sites that still name the deprecated package

Codex has a complete lineage contract; Claude has none — only a bare command
name, which is why a same-named binary of either lineage passes today.

| Location | Current value | Problem |
| --- | --- | --- |
| `internal/agent/acpx_runner.go:54` | `"claude": "claude-code-acp"` | default adapter command is the deprecated lineage |
| `internal/agent/acpx_runner.go:59` | `"claude-code-acp": "npm install -g @zed-industries/claude-code-acp"` | install hint installs the deprecated package |
| `internal/agent/acpx_runner.go:60` | `"claude-agent-acp": "npm install -g @zed-industries/claude-agent-acp"` | **wrong scope** — resolves to `@zed-industries/claude-agent-acp@0.23.1`, not the official `@agentclientprotocol/claude-agent-acp@0.63.0` |
| `internal/agent/acpx_runner.go:27-30` | `CodexAdapterPackage`, `PinnedCodexAdapterVersion`, `legacyCodexAdapterPackage`, `defaultCodexAdapterCommand` | Codex-only; no Claude equivalent exists |
| `docs/adr/0040-reasoning-effort-is-assigned-only-when-configured.md:7` | "claude-code-acp does not implement the reasoning config option at all" | premise is now false for the official adapter |

Test fixtures naming the deprecated command:
`internal/agent/acpx_runner_test.go:175,2693` and
`internal/cli/implement_test.go:4163`.

Both packages named `claude-agent-acp` exist on npm, so a lineage check cannot
rely on the command name alone: `@zed-industries/claude-agent-acp@0.23.1` and
`@agentclientprotocol/claude-agent-acp@0.63.0` are different lineages.

## Implementation instructions

1. Introduce the Claude counterparts of the Codex lineage constants —
official package `@agentclientprotocol/claude-agent-acp`, a pinned minimum
version, and `@zed-industries/claude-code-acp` plus
`@zed-industries/claude-agent-acp` as recognized legacy lineages. Make the
default Claude adapter command the official pinned form, matching how Codex
resolves `npx -y @agentclientprotocol/codex-acp@<pin>`.
2. Extend Adapter Readiness so Doctor and Setup prove Claude lineage the same
way they prove Codex: report the effective command, resolved package, and
version; classify a legacy lineage as a migration with the official install
action; and never accept a matching executable name as proof.
3. Fix the wrong-scope install command at `acpx_runner.go:60`.
4. Stop parsing `[...]` as an embedded reasoning effort when the adapter
advertises an independent reasoning control; treat the model identifier as
opaque so `opus[1m]` selects with an explicit effort. Keep the existing
variant encoding for adapters that genuinely use it, and cover both shapes
with tests.
5. Supersede ADR-0040's claim about Claude reasoning support, recording that
the official adapter advertises the reasoning control.
6. Update the operator docs and the Roundfix Skill pair so the Claude adapter
contract reads like the Codex one. The Skill pair edit changes its
`contentDigest` and requires the derived baseline/catalog digest pins to be
propagated under express authorization — see the Tooling authority entries
of archived Spec `0037-terminal-outcome-integrity`.

## Suggested acceptance checks

- Doctor on a machine whose `claude` command resolves to either
`@zed-industries` lineage fails with the official install action and does not
accept the name as proof.
- Doctor with `@agentclientprotocol/claude-agent-acp` at or above the pin
reports `adapter: ok` naming package and version for Claude as it does for
Codex.
- `claude / opus[1m] / xhigh` proves clean and applies `xhigh` through the
independent reasoning control.
- `claude / opus / 1m` no longer resolves an effort of `1m`.
- An adapter that really uses the `canonical[effort]` variant encoding keeps
working.
- No source, test, or documentation path outside `docs/findings/` and archived
Specs mentions `@zed-industries/claude-code-acp`.

## What worked — keep

- The dry-run tuple proof
(`profiles configure --dry-run`) diagnoses selection problems without writing
config or starting a Run, and its classifications (`missing_config_options`
versus `model_not_advertised`) were precise enough to separate an adapter
capability gap from a parsing defect.
- Roundfix's error message listing advertised models and efforts is what made
the bracket collision visible; keep that detail in selection failures.
Loading