Skip to content

Tag embedded subagent gap-fill rows as delivery mirrors#88687

Closed
alexzhu0 wants to merge 1 commit into
openclaw:mainfrom
alexzhu0:fix/subagent-announce-delivery-metadata
Closed

Tag embedded subagent gap-fill rows as delivery mirrors#88687
alexzhu0 wants to merge 1 commit into
openclaw:mainfrom
alexzhu0:fix/subagent-announce-delivery-metadata

Conversation

@alexzhu0

@alexzhu0 alexzhu0 commented May 31, 2026

Copy link
Copy Markdown
Contributor

Refs #87329 (Fix 1 — PRIMARY: tag echo messages correctly at write time)

Scope note: issue #87329 proposes two fixes — Fix 1 (PRIMARY: tag echo messages as openclaw/delivery-mirror at write time) and Fix 2 (DEFENSE IN DEPTH: merge consecutive assistant turns in validateAnthropicTurns). This PR implements Fix 1 only; Fix 2 is covered by the separate open PR #87346 (Jefsky). Using a non-closing Refs reference so merging this primary writer fix does not auto-close the issue before the defense-in-depth layer lands or maintainers accept that scope.

User-facing bug

Subagent announce / embedded handoff gap-fill can append a user-visible assistant mirror using the child runtime provider and model metadata, such as anthropic/claude-*, instead of marking the row as an OpenClaw transcript-only delivery mirror. Replay filters exclude transcript-only mirrors by provider: "openclaw" with model: "delivery-mirror" / gateway-injected, so a display-only mirror with child provider metadata can later be replayed back into a provider turn. In conversations with provider-managed thinking/signature blocks, that stale mirror can surface as errors like thinking blocks cannot be modified.

Exact repro

Source-level reproduction:

  1. Run persistCliTurnTranscript for an embedded assistant gap-fill with:
    • embeddedAssistantGapFill: true
    • result.meta.agentMeta.provider: "claude-cli" or another runtime provider
    • visible final text in result.meta.finalAssistantVisibleText
  2. Before this fix, the appended transcript assistant row used api: "cli", provider: "claude-cli", and model: "opus".
  3. That row is user-visible display state, not provider conversation state, so replay filters did not identify it as transcript-only.
  4. After this fix, the same gap-fill row is written as api: "openai-responses", provider: "openclaw", and model: "delivery-mirror".

Fix summary

  • Changed embedded assistant gap-fill transcript persistence to write assistant mirrors as openclaw/delivery-mirror.
  • Kept normal CLI transcript persistence unchanged: non-gap-fill CLI replies still preserve real CLI provider/model metadata and usage.
  • Added regression coverage so the gap-fill path asserts the transcript-only mirror metadata.

Metadata change (explicit callout)

This PR intentionally changes the persisted shape of embedded gap-fill assistant rows, so it is more than a replay fix — raw transcript / debug readers should be aware:

field before after
api "cli" "openai-responses"
provider child runtime provider (e.g. "claude-cli") "openclaw"
model child model (e.g. "opus") "delivery-mirror"
usage child usage block omitted

Scope is strictly the gapFill branch in persistCliTurnTranscript (src/agents/command/attempt-execution.ts:365). Normal (non-gap-fill) CLI rows are untouched and keep api:"cli" + real provider/model/usage.

Downstream api:"cli" consumers — verified none affected. The .api field is read only by the LLM transport/provider layer for foreign-tool-call detection (src/llm/providers/transform-messages.ts:100, openai-responses-shared.ts:202, comparing source.api === model.api). Gap-fill rows never reach those comparisons: rows tagged provider:"openclaw" + model:"delivery-mirror" are in TRANSCRIPT_ONLY_OPENCLAW_MODELS (src/agents/embedded-agent-runner/replay-history.ts:241) and are dropped from the replay copy before any provider prompt is built. Every other gap-fill/delivery-mirror filter in the tree keys on the provider/model pair, not api.

Targeted tests

  • Extended src/agents/command/attempt-execution.cli.test.ts to prove embedded gap-fill rows are tagged as openclaw/delivery-mirror.
  • Re-ran replay-history coverage to confirm delivery-mirror rows remain excluded from embedded provider replay.

Real behavior proof

Behavior addressed: Embedded subagent assistant gap-fill rows are now stored as OpenClaw delivery mirrors, so provider replay filters do not treat display-only text as provider conversation state.

Real environment tested: Local OpenClaw checkout on branch fix/subagent-announce-delivery-metadata, commit 5dcee2eae5, rebased onto current origin/main; Node v24.4.1.

Exact steps or command run after this patch:

  • git diff --check origin/main...HEAD
  • ./node_modules/.bin/oxlint src/agents/command/attempt-execution.ts src/agents/command/attempt-execution.cli.test.ts
  • node scripts/run-vitest.mjs src/agents/command/attempt-execution.cli.test.ts src/agents/embedded-agent-runner/replay-history.test.ts

Evidence after fix:

Writer and replay halves verified together. The merge-readiness ask is to show the gap-fill row is written as openclaw/delivery-mirror and is then excluded from the next provider prompt. These two real test suites prove the two halves of exactly that path end to end:

  • Writer half — src/agents/command/attempt-execution.cli.test.ts (25 tests passed): the embedded gap-fill assertion (embeddedAssistantGapFill: true) reads back the persisted transcript row and proves it is written as api: "openai-responses", provider: "openclaw", model: "delivery-mirror", while non-gap-fill CLI rows keep real provider/model metadata.
  • Replay half — src/agents/embedded-agent-runner/replay-history.test.ts (35 tests passed): normalizeAssistantReplayContent is given a history containing exactly that provider: "openclaw" / model: "delivery-mirror" row alongside a real provider reply, and the test asserts the delivery-mirror row is dropped from the replay copy (out length 2) while the real provider reply survives. That is the row never re-entering the provider prompt.

Together: the shape the writer persists (suite 1) is precisely the shape the replay filter excludes (suite 2). Copied terminal summary:

 src/agents/command/attempt-execution.cli.test.ts
      Tests  25 passed (25)

 src/agents/embedded-agent-runner/replay-history.test.ts
      Tests  35 passed (35)

[test] passed 2 Vitest shards in 134.85s
  • oxlint passed on the changed source and test files (exit 0).
  • git diff --check origin/main...HEAD passed.

Live replay-path output — ran a single script that chains the patched writer to the replay filter on real functions (no hand-built input): it writes a session store, calls persistCliTurnTranscript with embeddedAssistantGapFill: true, reads the persisted JSONL row back off disk, then passes that exact row through normalizeAssistantReplayContent (src/agents/embedded-agent-runner/replay-history.ts):

STEP 1 — patched persistCliTurnTranscript wrote this JSONL assistant row:
[
  {
    "role": "assistant",
    "api": "openai-responses",
    "provider": "openclaw",
    "model": "delivery-mirror",
    "content": [{ "type": "text", "text": "delivered to channel" }]
  }
]

STEP 2 — that exact persisted row passed through normalizeAssistantReplayContent:
  rows in: 3  rows out: 2
  persisted delivery-mirror row excluded from replay: true
  real provider reply retained: true

This is the full patched writer-to-replay path on real code: the patched writer persists the gap-fill row to disk as openclaw/delivery-mirror, and that exact persisted row is then excluded from the rebuilt replay (3 → 2 rows) so it never re-enters the provider prompt, while the genuine provider reply is retained.

Observed result after fix: Embedded gap-fill transcript rows use api: "openai-responses", provider: "openclaw", and model: "delivery-mirror" while normal CLI transcript rows still preserve real provider/model metadata.

What was not tested: No live provider-managed thinking/signature conversation was replayed end to end against a running embedded agent and a real provider. That path requires a live provider session, which was not available in this environment; the writer-to-replay contract is instead proven by the two connected real test suites above on the actual production functions (persistCliTurnTranscript output shape and normalizeAssistantReplayContent exclusion).

Not tested / known gaps

  • No external transcript/debug consumer was found in this checkout that depends on api: "cli" for embedded gap-fill rows, but external scripts that read raw transcript metadata may observe the intentional gap-fill metadata change from child CLI provider/model to openclaw/delivery-mirror.

AI-assisted disclosure

This patch was prepared with AI assistance. I used local code inspection, targeted regression tests, and explicit command output to validate the behavior above.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels May 31, 2026
@clawsweeper

clawsweeper Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 13, 2026, 9:14 AM ET / 13:14 UTC.

Summary
This PR changes embedded assistant gap-fill transcript persistence so future gap-fill rows are written as openai-responses / openclaw / delivery-mirror and adds a regression assertion for that shape.

PR surface: Source +7, Tests +9. Total +16 across 2 files.

Reproducibility: yes. at source level: current main writes gap-fill rows with CLI child metadata, while replay filtering drops only openclaw delivery-mirror or gateway-injected assistant rows. I did not run a live Anthropic gateway-restart replay.

Review metrics: 1 noteworthy metric.

  • Persisted gap-fill metadata: 1 assistant-row shape changed. Future embedded gap-fill rows no longer preserve child CLI api/provider/model/usage metadata, which matters for replay filtering and raw transcript readers.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Risk before merge

  • [P1] Raw transcript or debug consumers that key on api: "cli", child provider/model metadata, or child usage for embedded gap-fill rows will observe a deliberate persisted metadata shape change.
  • [P1] This PR covers the writer-side fix only; the linked issue and companion assistant-turn merge PR should stay open unless maintainers explicitly decide the writer fix is enough.
  • [P1] No live provider-managed thinking/signature replay after a gateway restart was run end to end; the supplied proof covers the production writer-to-replay contract on real functions.

Maintainer options:

  1. Accept delivery-mirror metadata (recommended)
    Land the PR with maintainer-visible acceptance that embedded gap-fill rows now use the transcript-only delivery-mirror metadata contract instead of child CLI metadata.
  2. Add a compatibility path first
    If maintainers know raw transcript readers require the old child metadata, preserve that need through a documented field, migration note, or reader update before merge.
  3. Pause for live replay proof
    If live Anthropic restart replay is required for this session-state path, pause until a redacted real-provider run proves the symptom no longer recurs.

Next step before merge

  • [P2] The remaining action is maintainer acceptance of the raw transcript metadata compatibility change and linked-issue scope, not a narrow automated code repair.

Security
Cleared: The diff only changes transcript metadata assignment and a focused test assertion; it does not touch secrets, dependencies, workflows, install scripts, package metadata, or other code-execution surfaces.

Review details

Best possible solution:

Land the narrow writer-side delivery-mirror tagging if maintainers accept the raw transcript metadata compatibility change, while keeping the linked issue or companion hardening path open for the remaining defense-in-depth decision.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: current main writes gap-fill rows with CLI child metadata, while replay filtering drops only openclaw delivery-mirror or gateway-injected assistant rows. I did not run a live Anthropic gateway-restart replay.

Is this the best way to solve the issue?

Yes: tagging the display-only row correctly at write time is the narrowest primary fix because the replay and transcript mirror code already define openclaw/delivery-mirror as transcript-only. The assistant-turn merge path remains useful defense-in-depth, not a replacement for this writer fix.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 78c66742ab97.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes local command output and a live-output script chaining persistCliTurnTranscript output into normalizeAssistantReplayContent on real production functions, which is sufficient for the changed writer-to-replay contract.

Label justifications:

  • P1: The linked bug can make active agent sessions repeatedly fail provider replay after a gateway restart when provider-managed thinking/signature blocks are present.
  • merge-risk: 🚨 compatibility: The PR intentionally changes persisted raw transcript metadata for embedded gap-fill assistant rows that external or debug tooling may read.
  • merge-risk: 🚨 session-state: Persisted transcript metadata determines whether assistant rows are replayed into future provider turns, so the change affects session replay semantics.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes local command output and a live-output script chaining persistCliTurnTranscript output into normalizeAssistantReplayContent on real production functions, which is sufficient for the changed writer-to-replay contract.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes local command output and a live-output script chaining persistCliTurnTranscript output into normalizeAssistantReplayContent on real production functions, which is sufficient for the changed writer-to-replay contract.
Evidence reviewed

PR surface:

Source +7, Tests +9. Total +16 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 13 6 +7
Tests 1 10 1 +9
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 23 7 +16

What I checked:

  • Current main writer path: On current main, persistCliTurnTranscript computes gapFill but still passes assistant metadata as api: "cli", child provider, child model, and child usage for both normal CLI rows and gap-fill rows. (src/agents/command/attempt-execution.ts:401, 78c66742ab97)
  • Runtime caller: agent-command marks embedded runner output or visible final assistant text as embeddedAssistantGapFill before calling persistCliTurnTranscript, so the changed writer is on the reported runtime path. (src/agents/agent-command.ts:2009, 78c66742ab97)
  • Replay exclusion contract: normalizeAssistantReplayContent drops assistant rows only when isTranscriptOnlyOpenClawAssistantMessage recognizes them, and that shared predicate requires provider: "openclaw" with model: "delivery-mirror" or gateway-injected. (src/agents/embedded-agent-runner/replay-history.ts:321, 78c66742ab97)
  • Existing mirror shape: The canonical delivered-outbound transcript mirror writer already persists delivery mirrors as api: "openai-responses", provider: "openclaw", and model: "delivery-mirror", matching the PR's gap-fill target shape. (src/config/sessions/transcript.ts:273, 78c66742ab97)
  • Provider .api consumers checked: The searched .api consumers that compare assistant source metadata against the active model are in provider transport/replay conversion, while delivery-mirror filtering is keyed on provider/model before replay reaches those provider prompt builders. (src/llm/providers/transform-messages.ts:97, 78c66742ab97)
  • PR diff: The PR changes only the gap-fill assistant metadata branch to openai-responses / openclaw / delivery-mirror; normal non-gap-fill CLI rows continue using api: "cli", child provider/model, and usage. (src/agents/command/attempt-execution.ts:365, 5dcee2eae584)

Likely related people:

  • Ayaan Zaidi: git log -S 'persistCliTurnTranscript' shows commit b8ef507cc08217ef74fab74619dbcb22ee25f9fe introduced the CLI transcript persistence path that currently writes child metadata for gap-fill rows. (role: introduced behavior; confidence: high; commits: b8ef507cc082; files: src/agents/command/attempt-execution.ts, src/agents/agent-command.ts)
  • Peter Steinberger: The delivered-outbound transcript mirror helper and initial delivery-mirror metadata contract date to fdaeada3ec76b39702de6ad2edcc1cb39869b45d, which is the sibling contract this PR reuses. (role: feature owner; confidence: medium; commits: fdaeada3ec76; files: src/config/sessions/transcript.ts)
  • Andy: Commit e95efa437381cc177c6c6fa6c26d7b25eab37be8 recently refined delivery-mirror dedupe semantics in the transcript writer, adjacent to the persisted mirror metadata contract. (role: adjacent contributor; confidence: medium; commits: e95efa437381; files: src/config/sessions/transcript.ts)
  • Hansraj Singh Thakur: Current-line blame on the central agent writer, replay filter, and transcript helper points to ab559a7257d9b6eace7abfb2cdf0ad8ac76e6511, a recent broad touch to adjacent agent/channel progress behavior. (role: recent area contributor; confidence: low; commits: ab559a7257d9; files: src/agents/command/attempt-execution.ts, src/agents/agent-command.ts, src/agents/embedded-agent-runner/replay-history.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels May 31, 2026
@byungskers

Copy link
Copy Markdown

Nice catch. I like that this keeps the gap-fill rows on the existing provider: "openclaw" / model: "delivery-mirror" replay contract instead of teaching every replay filter about more child-provider-shaped mirrors.

One small follow-up question: do we have any downstream transcript/debug tooling that keys off api: "cli" for these rows today? If not, openai-responses/openclaw/delivery-mirror seems much safer; if yes, it may be worth calling out the metadata change explicitly in the PR body so nobody assumes this is only a replay fix.

@alexzhu0
alexzhu0 marked this pull request as ready for review June 1, 2026 02:05
@alexzhu0
alexzhu0 force-pushed the fix/subagent-announce-delivery-metadata branch from ac11ae0 to 24ccf84 Compare June 1, 2026 02:23
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 1, 2026
@alexzhu0
alexzhu0 force-pushed the fix/subagent-announce-delivery-metadata branch from 24ccf84 to b1764cf Compare June 2, 2026 03:08
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Jun 2, 2026
Embedded assistant gap-fill transcript rows are display-only delivery state. Store them as OpenClaw delivery mirrors so provider replay filters do not mistake child provider text for provider conversation state.

Constraint: Embedded gap-fill transcript rows are display-only state and must match existing transcript-only replay filters.

Rejected: Preserve child runtime provider/model metadata for gap-fill rows | that makes display mirrors look like provider conversation state.

Confidence: high

Scope-risk: narrow

Directive: Do not tag embedded assistant gap-fill mirrors with child provider/model metadata unless replay filters are updated with an equivalent transcript-only contract.

Tested: git diff --check origin/main...HEAD; oxlint changed files; targeted Vitest attempt-execution/replay-history suites (3 files, 95 passed); tsgo core-test project; codex review --base origin/main.

Not-tested: No live provider-managed thinking/signature conversation was replayed end to end; external raw transcript consumers may observe the intentional gap-fill metadata change.
@alexzhu0
alexzhu0 force-pushed the fix/subagent-announce-delivery-metadata branch from b1764cf to 5dcee2e Compare June 2, 2026 17:27
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 2, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 2, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 2, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 4, 2026
@alexzhu0

Copy link
Copy Markdown
Contributor Author

No downstream tooling keys off api: "cli" for these gap-fill rows, so openai-responses/openclaw/delivery-mirror is the safe choice.

The only readers of the .api field are in the LLM transport/provider layer, where it's compared against the active model for foreign-tool-call detection (src/llm/providers/transform-messages.ts:100, src/llm/providers/openai-responses-shared.ts:202source.api === model.api). Gap-fill rows never reach those comparisons: once tagged provider:"openclaw" + model:"delivery-mirror", they land in TRANSCRIPT_ONLY_OPENCLAW_MODELS (src/agents/embedded-agent-runner/replay-history.ts:241) and are dropped from the replay copy before any provider prompt is built. Every other gap-fill / delivery-mirror filter in the tree keys on the provider/model pair, never on api.

I took your second point and made the shape change explicit rather than implicit — added a "Metadata change" callout to the PR body with a before/after table (api, provider, model, usage) and the scope note that only the gapFill branch is affected, so this doesn't read as a replay-only fix to a raw-transcript reader.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 13, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 13, 2026
@steipete

Copy link
Copy Markdown
Contributor

Closing this because the proposed metadata change breaks the shipped embedded gap-fill contract.

embeddedAssistantGapFill was introduced in #77839 to persist the assistant's visible text when the embedded runner did not leave a canonical assistant row in session JSONL. It is therefore not always a redundant delivery echo. On this PR head, I ran the real persistCliTurnTranscript output through normalizeAssistantReplayContent from an initially empty transcript:

  • the writer persisted the only assistant answer as provider: "openclaw", model: "delivery-mirror";
  • replay then removed that exact row;
  • the rebuilt history contained only the user turn, so the model lost its prior answer.

The duplicate-row failure mode is already handled at the correct boundary by tail dedupe, including trailing custom rows, in #83635. The consecutive-assistant Anthropic failure is now fixed structurally by #87346, which preserves signed thinking/tool-call blocks and passed a live Anthropic tool-result-adjacency test plus the full CI matrix.

Evidence that would change this decision: a narrower writer distinction proving a specific gap-fill row is redundant while preserving missing-canonical-turn fallback rows, with an end-to-end test showing both replay exclusion for the redundant case and replay retention for the only-answer case.

Thanks for the careful investigation and proof work here; it exposed an important ownership distinction even though this metadata rewrite is not safe to land.

@steipete steipete closed this Jun 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants