Skip to content

Project a task-notification delivered as an attachment - #1045

Merged
alexeyzimarev merged 2 commits into
mainfrom
subagent-notification-attachments
Sep 19, 2026
Merged

alexeyzimarev merged 2 commits into
mainfrom
subagent-notification-attachments

Conversation

@alexeyzimarev

Copy link
Copy Markdown
Member

Closes #1041 — AI-2990

What & why

The chat's subagent strip and SUBAGENTS section read a subagent's end from the transcript's task-notification, and the Claude leaf projected only user and assistant records. Claude Code writes a notification that lands while the parent is mid-turn as an attachment record (attachment.type: queued_command, commandMode: task-notification, the notification in prompt), so most background agents never got their finish signal and the strip kept counting them. The leaf now projects that attachment as the user line it would otherwise have been, with origin_kind: task-notification; the rules and the tracker are unchanged, and every other attachment type stays ignored.

Where to look

ClaudeTranscriptEvents.ProjectAttachment: only a queued_command in task-notification mode passes; a queued user prompt, a prompt snapshot or a file still project nothing, and the event id is the record's own uuid, as for a user line. A notification delivered both ways (mid-turn, then again once idle) settles its row once and shows its note twice.

Verification

  • dotnet run --project test/Capacitor.Models.Transcripts.Tests.Unit/Capacitor.Models.Transcripts.Tests.Unit.csproj — 151 total, 0 failed
  • dotnet run --project test/Capacitor.Cli.Core.Tests.Unit/Capacitor.Cli.Core.Tests.Unit.csproj -- --treenode-filter "/*/*/ClaudeChatRulesTests/*" — 28/28; TranscriptChatCanonicalTests 8/8
  • dotnet publish src/Capacitor.Cli/Capacitor.Cli.csproj -c Release 2>&1 | grep -E 'IL[23][01][0-9]{2}' — no output
  • On the session that showed the defect: 45 launches, 41 notifications present only as attachments, 3 both ways, 1 as a user line only

🤖 Generated with Claude Code

Claude Code writes a notification that lands mid-turn as a
queued_command attachment, never as the user line the chat rules
read, so the leaf projects that shape as if it were one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-19T09:58:33.042700Z ff3af62 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Project task-notification attachments as subagent completions

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Project mid-turn task-notification attachments as canonical user messages.
• Preserve record identity, sidechain metadata, and task-notification origin for downstream rules.
• Verify subagent completion while ignoring unrelated attachment forms.
Diagram

graph TD
    A["Claude attachment"] --> B{"Task notification?"} -->|Yes| C["Transcript projector"] --> D["Canonical user event"] --> E["Chat rules"] --> F["Tracker and note"]
    B -->|No| G["Ignore attachment"]
Loading
High-Level Assessment

Projecting this Claude-specific record shape at the transcript normalization boundary is the best approach. It preserves the existing canonical event contract, chat rules, and tracker behavior while narrowly filtering unrelated attachments; handling raw attachments downstream would leak provider-specific transcript details into higher layers.

Files changed (4) +88 / -5

Bug fix (1) +21 / -3
ClaudeTranscriptEvents.csProject queued task-notification attachments +21/-3

Project queued task-notification attachments

• Recognizes attachment records and projects only queued_command task notifications with prompts into canonical user messages. Preserves record identity, timestamps, parent linkage, and sidechain state while setting origin_kind to task-notification.

src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs

Tests (2) +62 / -2
ClaudeChatRulesTests.csVerify attachment notifications finish subagents +23/-1

Verify attachment notifications finish subagents

• Confirms projected attachment notifications produce completion notes and finished subagent signals. Also verifies ordinary queued prompts remain ignored.

test/Capacitor.Cli.Core.Tests.Unit/Harness/Claude/ClaudeChatRulesTests.cs

ClaudeTranscriptEventsTests.csCover attachment projection and filtering +39/-1

Cover attachment projection and filtering

• Tests successful task-notification projection, record metadata, origin flags, and sidechain propagation. Covers malformed and unrelated attachment variants to ensure they remain ignored without rejection.

test/Capacitor.Models.Transcripts.Tests.Unit/Harness/Claude/ClaudeTranscriptEventsTests.cs

Documentation (1) +5 / -0
CHANGES.mdDocument mid-turn notification attachment handling +5/-0

Document mid-turn notification attachment handling

• Explains why Claude Code stores mid-turn subagent notifications as attachments and how they are projected. Clarifies that duplicate delivery settles the subagent once while displaying both notes.

docs/CHANGES.md

@qodo-code-review

qodo-code-review Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unrelated attachments are rejected ✓ Resolved 🐞 Bug ≡ Correctness
Description
Project admits every attachment to the shared record UUID validation before ProjectAttachment
determines whether its subtype is relevant. A queued prompt, snapshot, file, or other ignored
attachment with a malformed UUID therefore returns a rejection instead of projecting nothing.
Code

src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[38]

+            if (type is not ("user" or "assistant" or "attachment")) return ProjectionResult.Empty;
Relevance

●●● Strong

Trivial ordering bug: ignored attachments must bypass UUID validation, matching the projection
contract and existing ignored-record behavior.

PR-#1003

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The expanded type guard admits every attachment before lines 40–49 validate its UUID, while
ProjectAttachment only later ignores nonmatching shapes. The projection contract distinguishes
rejected unusable records from empty ignored records, and the new tests explicitly expect unrelated
attachments to be ignored without covering malformed UUIDs.

src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[35-49]
src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[129-132]
src/Capacitor.Models.Transcripts/CanonicalEvent.cs[32-43]
test/Capacitor.Models.Transcripts.Tests.Unit/Harness/Claude/ClaudeTranscriptEventsTests.cs[164-176]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
All attachment records now undergo UUID validation before irrelevant attachment subtypes are filtered, so an attachment that should be ignored is rejected when its UUID is malformed.

## Fix Focus Areas
- src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[35-58]
- src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[126-137]
- test/Capacitor.Models.Transcripts.Tests.Unit/Harness/Claude/ClaudeTranscriptEventsTests.cs[164-177]

## Recommended Fix
Recognize whether an attachment is a queued task-notification before performing shared record validation. Keep UUID validation for matching task-notification attachments, and add tests proving an irrelevant attachment with a malformed UUID is ignored while a matching notification with the same malformed UUID is rejected.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Meta notifications appear in chat ✓ Resolved 🐞 Bug ≡ Correctness
Description
ProjectAttachment calls ClaudeCodeExtension.Flags without forwarding the attachment record's
root isMeta value. When a task-notification attachment is marked meta, chat filtering sees no meta
flag and renders its system note even though equivalent user-record notifications stay hidden while
still finishing the subagent.
Code

src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[R134-135]

+        var emitter = new Emitter(record);
+        emitter.Add(0, UserMessage(prompt, record), ClaudeCodeExtension.Flags(record.IsSidechain, originKind: "task-notification"));
Relevance

●●● Strong

Missing metadata propagation causes a clear chat-filtering correctness regression; analogous
event-state propagation fixes were accepted recently.

PR-#1016
PR-#1031

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Ordinary user projection forwards isMeta, and the extension only writes is_meta when that
argument is true; the new attachment path omits it. Chat filtering hides events carrying this flag,
while subagent completion intentionally ignores it, and the existing meta-notification test
establishes that hidden-note plus retained-finish behavior.

src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[77-79]
src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[129-136]
src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeCodeExtension.cs[17-25]
src/Capacitor.Cli.Core/Harness/Claude/ClaudeChatRules.cs[34-40]
src/Capacitor.Cli.Core/Harness/Claude/ClaudeChatRules.cs[53-77]
test/Capacitor.Cli.Core.Tests.Unit/Harness/Claude/ClaudeChatRulesTests.cs[255-261]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Task-notification attachments discard the root isMeta flag, so meta notifications become visible chat notes instead of remaining hidden while delivering their completion signal.

## Fix Focus Areas
- src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs[129-136]
- test/Capacitor.Models.Transcripts.Tests.Unit/Harness/Claude/ClaudeTranscriptEventsTests.cs[179-200]
- test/Capacitor.Cli.Core.Tests.Unit/Harness/Claude/ClaudeChatRulesTests.cs[236-253]

## Recommended Fix
Read the attachment record's root isMeta value and pass it to ClaudeCodeExtension.Flags alongside isSidechain and origin_kind. Add projection and chat-rule tests proving a meta attachment retains is_meta, emits the subagent finish signal, and produces neither a displayed envelope nor submitted input.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 64 rules
✅ Cross-repo context — repo relationships
  Explored: repo: kurrent-io/kurrent-agents (sha: 8bf78d4f)
Review mode: ⚖️ Balanced: This is a localized but behavior-changing transcript projection on a task-notification path, with parsing, identity, timestamp, sidechain, and downstream rule interactions that merit a complete review but are not dense enough for extended.

Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/Capacitor.Models.Transcripts/Harness/Claude/ClaudeTranscriptEvents.cs Outdated
An attachment the leaf does not read is ignored whatever its uuid
holds, and meta hides a notification's row on either delivery.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Desktop: subagent rows never finish when the task-notification arrives as an attachment

1 participant