Skip to content

fix(trace): attribute failed, overlapping and cross-checkout shell edits to the AI - #3521

Merged
migmartri merged 4 commits into
mainfrom
fix/trace-shell-attribution
Oct 5, 2026
Merged

migmartri merged 4 commits into
mainfrom
fix/trace-shell-attribution

Conversation

@migmartri

@migmartri migmartri commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Summary

The CLI attributed some AI-made file changes to a human in AI coding session evidence. This PR fixes three causes in the shell-command attribution of chainloop trace.

  • Failed shell commands. Claude Code runs the PostToolUseFailure hook, not PostToolUse, when a tool call fails. A failed command can still change files. The CLI now installs the post-tool-use handler for PostToolUseFailure too. A failed call expects a different hook response, so pending session links stay on disk for the next command that succeeds.
  • Overlapping shell commands of one agent. The pre-command snapshot was stored per session and agent. Two overlapping commands of one agent overwrote each other's snapshot. The snapshot is now stored per tool call, with Claude's tool_use_id and opencode's callID. Agents without a call ID keep the per-agent slot.
  • Shell edits in another checkout. Shell hooks run in the session's own checkout, so they did not see a command like cd <other checkout> && .... When a file tool edits a file in another checkout, the CLI now adds that checkout to the session record. Shell hooks then also snapshot each listed checkout, and record its changes in the ledger of that checkout.

Existing installations get the new Claude Code hook when they run chainloop trace init again.

Known limits

Refs #3519

This PR was made with AI assistance (Claude Code).

🤖 Posted by Maximus bot (Claude Code) on behalf of @migmartri

Review in cubic

Claude Code fires PostToolUseFailure, not PostToolUse, when a tool call
fails. The CLI installed only PostToolUse, so a command that wrote files
and then exited with an error left those files attributed to a human.

Install the post-tool-use handler for PostToolUseFailure too. A failed
call expects a different hook response, so pending session links stay on
disk for the next command that succeeds.

Refs #3519

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 21c8f01a-33fb-437e-bbe6-f1ea822a7a5e
The pre-command working-tree signature was keyed by session and agent.
When one agent ran overlapping shell commands, the second pre hook
replaced the first command's signature, and the first post hook deleted
the second's. The files of one command were then attributed to a human.

Key the signature by the agent's tool call ID when the agent reports
one: Claude's tool_use_id, and opencode's callID, which the plugin now
passes. Agents without call IDs keep the per-agent slot.

Refs #3519

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 21c8f01a-33fb-437e-bbe6-f1ea822a7a5e
Shell hooks run in the session's own checkout and snapshot only that
checkout. When the agent changed files in another checkout with a
command like `cd <other checkout> && ...`, those files were attributed
to a human, even though file tool edits in the same checkout were
attributed to the AI.

When a file tool edits a file in another checkout, add that checkout to
the session record of the session's own checkout. Shell hooks now also
snapshot each listed checkout and record its changes in that
checkout's ledger. A checkout that the session never edited with a file
tool is still not snapshotted.

Refs #3519

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 21c8f01a-33fb-437e-bbe6-f1ea822a7a5e
@migmartri migmartri self-assigned this Oct 5, 2026
@chainloop-platform

chainloop-platform Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

AI Session Checks — 🟢 93% · ✅ 0 failing

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟢 93% 1 ✅ 0 100% AI / 0% Human 12 +556 / -107 52m30s

🟢 93% — 100% AI — ✅ All policies passing

Oct 5, 2026 11:13 UTC · 52m30s · $20.66 · 570 in / 254.7k out · claude-code 2.1.289 (claude-opus-5-5)

View session details ↗

Change Summary

  • Adds PostToolUseFailure handling so failed shell commands still attribute changed files.
  • Keys shell pre-snapshots by tool call ID, including opencode tool_use_id.
  • Tracks foreign checkouts on the session record so shell edits there are attributed correctly.
  • Adds regression tests, reruns the trace/action suites, and follows up on the opencode review fix.

AI Session Overall Score

🟢 93% — Well-planned, focused fixes with strong validation and no visible user friction.

AI Session Analysis Breakdown

🟢 96% · verification

🟢 The AI validated the fixes with failing-first tests and a real-binary e2e run. · High Impact

🟢 94% · context-and-planning

🟢 A detailed approved plan landed before the substantive implementation began. · High Impact

🟢 93% · alignment

No notes.

🟢 91% · solution-quality

No notes.

🟢 90% · user-trust-signal

No notes.

🟢 89% · scope-discipline

🟢 The AI kept the work bounded to fixes 1–3, then a specific review-comment fix. · Medium Impact


File Attribution

████████████████████ 100% AI / 0% Human

Status Attribution File Lines
modified ai app/cli/pkg/action/trace_agent_hook_test.go +194 / -4
modified ai app/cli/pkg/action/trace_agent_hook.go +150 / -32
modified ai app/cli/internal/trace/state/snapshot_test.go +77 / -45
modified ai app/cli/internal/trace/state/snapshot.go +48 / -25
modified ai app/cli/internal/trace/claude/hooks_test.go +40 / -0
modified ai app/cli/internal/trace/opencode/hooks_test.go +10 / -0
modified ai app/cli/internal/trace/claude/hooks.go +8 / -1
modified ai app/cli/internal/trace/provider.go +9 / -0
modified ai app/cli/internal/trace/opencode/hooks.go +6 / -0
modified ai app/cli/internal/trace/state/session.go +6 / -0
modified ai app/cli/internal/trace/opencode/testdata/plugin_full.ts +4 / -0
modified ai app/cli/internal/trace/opencode/testdata/plugin_tracerun.ts +4 / -0

Policies (4)

Status Policy Material Messages
✅ Passed ai-config-ai-agents-allowed ai-coding-session-21c8f0 -
✅ Passed ai-config-no-dangerous-commands ai-coding-session-21c8f0 -
✅ Passed ai-config-no-secrets ai-coding-session-21c8f0 -
✅ Passed ai-config-mcp-servers-allowed ai-coding-session-21c8f0 -

Security Checks — ✅ 5 passing

✅ secret-scan

Status Policy Messages
✅ Passed secrets-detection -

✅ sast-scan

Status Policy Messages
✅ Passed owasp-top10-2025 -
✅ Passed sast -
✅ Passed cwe-top25 -
✅ Passed cwe-top26-40-cusp -

security-context — 2 advisories

This change touches code with a recorded security-fix history. These are pointers to what past fixes established, not findings in this diff, and they never fail the check.

View security context ↗ · Security context documentation ↗

⏭️ 3 scans not applied

Scan Reason
vulnerability-scan no manifest/lockfile changed
github-actions-scan no workflow files changed
iac-scan no IaC files changed

View attestation ↗


PR validation — ✅ 3 passing

Status Policy Material Messages
✅ Passed pr-min-approvals pr-info -
✅ Passed pr-description-required pr-info -
✅ Passed pr-user-story-linked pr-info -

View attestation ↗


Powered by Chainloop and Chainloop Trace

@migmartri
migmartri requested a review from a team October 5, 2026 11:45

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 11 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread app/cli/internal/trace/opencode/hooks.go
Comment thread app/cli/internal/trace/state/snapshot_test.go
Comment thread app/cli/pkg/action/trace_agent_hook.go
The opencode plugin sends callID as tool_use_id on shell hooks, but the
opencode hook reader did not decode it. Overlapping opencode shell
commands then still shared one pre-command snapshot slot.

Refs #3519

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 21c8f01a-33fb-437e-bbe6-f1ea822a7a5e
@migmartri
migmartri merged commit 3733bb4 into main Oct 5, 2026
17 checks passed
@migmartri
migmartri deleted the fix/trace-shell-attribution branch October 5, 2026 15:03
javirln added a commit that referenced this pull request Oct 5, 2026
Main now sends the tool call ID as tool_use_id on the shell hooks, so
that overlapping commands keep their own snapshots (#3521). The plugin
is rewritten on this branch, so both of its entry points send it:
OpenCode 1.x names the ID callID, and OpenCode 2 names it id.

Assisted-by: Claude Code
Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
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.

2 participants