Skip to content

fix(runtime-host): admit structured-only Messages and keep them model-visible - #4815

Open
ggbdpq wants to merge 2 commits into
apache:mainfrom
ggbdpq:fix/structured-only-message-admission
Open

fix(runtime-host): admit structured-only Messages and keep them model-visible#4815
ggbdpq wants to merge 2 commits into
apache:mainfrom
ggbdpq:fix/structured-only-message-admission

Conversation

@ggbdpq

@ggbdpq ggbdpq commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #4804. Quote-only and attachment-only turns carried real model-facing context but were rejected twice on the way to the model, both times by a text-only admission assumption:

  1. Host admissiondecodeMessageAdmissionContent threw Invalid Message text for empty inline text unless skill ids were present, so a staged quote or a lone attachment could not be submitted.
  2. Replay visibilityruntimeEventHasModelVisibleContent counted only inline text length, so a persisted user event with empty text and a non-empty quotes array was dropped as blocking-unsupported, producing the durable current-run projection is not replayable / empty_text_skipped failure the issue records.

Now decodeMessageAdmissionContent applies the rule itself after structural decode — empty inline text is admissible when the Message carries quotes or attachments, and a Message with none of the three still throws the same invalid-frame error — and the visibility predicate counts structured user context (quotes/attachments) as model-visible. All turn/message admission call sites share the one function, and the model projection already renders quotes (formatQuoteRefs), so structured-only turns now reach the model with their content.

Verification

Claim Command Result
New tests pass with the fix node --test --test-name-pattern="#4804" on core runtime-event + runtime-host protocol dist tests 2 tests, 2 pass
Red-green stash the two production files, rebuild, rerun 2 tests, 2 fail; restored → pass
Quote-only admission at the frame level turn.message.submit with {text:'', quotes:[…]} / {text:'', attachments:[…]} admitted; {text:''} alone still Invalid Message text
No admission regression protocol.test.js (78), message-coordinator.test.js (73) all pass
Format npm run format:check exit 0

Known Windows-environment failures encountered while verifying, both reproduced identically with these production files stashed (control runs) and therefore pre-existing: hosted linked child roots share admission… (EBUSY unlink of a temp runtime.sqlite) and one EPIPE shutdown test in host-kernel. The full Runtime Host suite additionally stalls on this machine on an unrelated file; CI on Linux/macOS is the authoritative full-suite run.

Scope note: the renderer-side empty user bubble beside a quote chip is a display projection and is not addressed here; the durable event and the model request are correct after this change.

AI use

Implemented with ZCode (GLM-5.3-Flash): traced the issue's four named boundaries to the two blocking ones, applied the smallest contract change at each, and added red-green tests tagged with the issue number. The commit carries the Generated-by trailer.

Checklist

  • Root-cause fix at shared admission/visibility points, not per-surface patches
  • Regression tests fail on the old code (verified via stash/rebuild)
  • Test style follows each file's existing conventions, issue number in test names
  • No new dependencies; renderer display left as a stated follow-up

…-visible

A quote-only or attachment-only turn carried real model-facing context but
was rejected at the Host admission boundary ("Invalid Message text") and,
once persisted, dropped by the replay visibility predicate, which counted
only inline text length. The result was exactly apache#4804: structured-only
sends fail before the provider request, and any that persisted render as
an empty user bubble while the model never sees the quoted content.

- decodeMessageAdmissionContent now decodes the frame structurally and
  applies the text rule itself: empty inline text is admissible when the
  Message carries quotes or attachments; a Message with none of the three
  still throws the same invalid-frame error. All turn/message admission
  call sites share this function, so skill-only and structured-only
  admissions now follow one rule.
- runtimeEventHasModelVisibleContent counts a user-authored text event
  with quotes or attachments as model-visible even when the text is
  empty, so the durable event survives replay and the existing quote
  projection (formatQuoteRefs) reaches the model.

Red-green: both new tests (apache#4804-tagged) fail with the production files
stashed and pass with them restored.

Fixes apache#4804

Generated-by: GLM-5.3-Flash (ZCode)
@github-actions github-actions Bot added the effort/S Under 100 readable lines label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/S Under 100 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

desktop: quote-only and attachment-only messages require inline text

1 participant