Skip to content

[Bug] Kiro-native text-match resolver misattributes file attachments to the wrong persisted message #5409

Description

@gitnocknock

Description

Kiro-native sessions match an incoming persisted message back to its queued
web-composer entry via resolve_matching_text() in
omnigent/runtime/pending_inputs.py. The match condition is:
needle == entry_text or needle.endswith(entry_text)

The endswith branch is an unanchored suffix check, not a word-boundary
match. If a short queued entry's text (e.g. "ok") happens to be a trailing
substring of a later, unrelated accepted prompt (e.g. "Let's continue - ok"),
the resolver matches the wrong queued entry.

Because the caller (omnigent/server/routes/_sessions/orchestration.py,
_apply_kiro_pending_match area) merges the matched entry's file/image
blocks into the persisted item, this misattributes attachments: an image
the user attached to message A ends up permanently attached to unrelated
message B in the durable transcript. Meanwhile the real message that should
have matched gets re-persisted separately, out of order, and mislabeled
with a kiro_native_prompt_not_recorded error.

This is silent data corruption in conversation history with no workaround
once persisted; transcripts aren't user-editable.

I traced this to the original Kiro harness commit (#899); the endswith
branch has no test coverage, and Kiro's own JSONL parsing
(kiro_native_session_forwarder.py) confirms it never prepends or appends
text to prompts, so there's no legitimate case that requires anything
looser than exact-text equality.

Whats supposed to be happening is that a queued entry is only ever matched to the persisted message
whose text is identical to it. A miss should fall through to the existing
"no match" path (treated as typed directly in the terminal) rather than
guessing.

Steps to reproduce

  1. Start a Kiro-native session.
  2. From the web composer, send a short message with an attached image,
    e.g. "ok" + an image attachment. This queues a pending-input entry.
  3. Before Kiro's JSONL round-trips that specific message back through the
    transcript forwarder, send a second, unrelated message whose text ends
    in the same text, e.g. "Let's continue - ok".
  4. When Kiro mirrors "Let's continue - ok" back through the transcript,
    resolve_matching_text() matches it against the queued "ok" entry
    (unanchored suffix match) instead of waiting for the literal "ok"
    message.

Version

0.11.0.dev0

OS

macOS 15.5

Harness

Kiro

Harness mode

Native

Platform or device

macOS

Observed impact

One narrow or edge case

Authentication type

Not authentication-related

Metadata

Metadata

Assignees

Labels

BugSomething isn't workingP2-mediumPriority: bug with workaround, important feature requestcomp:harness-t3Lower-usage harnessescomp:reprComponent: serialization, representation layertriagedIssue has been triaged by the bot

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions