Files
PaperClipAI/doc
DottaandPaperclip 743698e700 fix(runner): preserve OpenCode bash process exit codes (#18076)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native Runner stores structured tool events so people can inspect
actual work.
> - OpenCode puts a completed bash command's process exit in
`state.metadata.exit`.
> - The canonical event mapper only read `state.exit`, so a real nonzero
exit became unknown.
> - This pull request preserves the documented builtin bash exit and
rejects conflicting evidence.
> - The benefit is an accurate process exit without changing tool
completion or native run status.

## Linked Issues or Issue Description

**What happened?**

A completed OpenCode bash part with `state.metadata.exit: 37` produced
`exitCode: null`. The process result was present, but the canonical tool
event lost it. The pinned upstream [shell
result](https://github.com/anomalyco/opencode/blob/v1.18.34/packages/opencode/src/tool/shell.ts#L544-L552)
and [completed
part](https://github.com/anomalyco/opencode/blob/v1.18.34/packages/opencode/src/session/processor.ts#L160-L170)
establish the field path.

**Expected behavior**

The canonical event retains the numeric process exit from a completed
builtin bash part. A completed tool call can have a nonzero command
exit. Missing or invalid evidence must not become a successful command.

**Steps to reproduce**

1. Pass a `type: "tool"`, `tool: "bash"` part with completed state and
numeric `metadata.exit` to `canonicalProviderEventsFromOpenCodePart`.
2. Inspect `tool.execution.completed.payload.exitCode`.
3. Before this fix, the value is null. After this fix, it matches the
process exit.

**Paperclip version or commit**

Reproduced on master `f4f02880cae4f5fa54d47d39565ca99b6b72446d`.
Duplicate searches found no matching fix. Related PR #15715 concerns
OpenCode V2 transport and version support; it does not change this
mapper.

## What Changed

- Read numeric metadata exits only from completed builtin bash parts.
- Keep legacy numeric top-level exits. Return unknown when supplied
legacy evidence conflicts.
- Cover zero and nonzero exits, invalid values, foreign tools,
incomplete calls and conflicting receipts.
- Document the run-log field and the distinction between tool completion
and command success.

## Verification

- The regression suite first failed five assertions on the unchanged
mapper. All 53 provider-event tests now pass.
- A focused no-emit TypeScript check covers the changed mapper, its
tests and imported protocol validators.
- Tests use synthetic structured parts and real protocol validation. No
local database, provider, SDK build or live scenario was run.
- All 48 jobs in the normal PR workflow passed, including the required
`ci / verify` and `ci / e2e` gates. CI also executed all 53
provider-event tests.
- Greptile reviewed this exact head at 5/5 with no actionable findings.
The separate hosted quality-gate review also completed successfully.

## Risks

- Conflicting legacy and metadata exits now remain unknown for completed
builtin bash calls. This avoids selecting one inconsistent value as
proof.
- Other tools retain their existing legacy behavior. Output prose never
supplies an exit code.
- The change adds no schema field and changes no provider version,
budget, accounting, fixture or native run outcome.

## Model Used

OpenAI `gpt-6.1-sol` through Codex, with reasoning and terminal tools.
The session does not expose the context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 15:11:22 -05:00
..
2026-02-16 14:25:00 -06:00