UAT: JSON/YAML envelope messages field is an empty dict {} instead of spec-required list of {level, text} objects #1879

Open
opened 2026-04-03 00:04:30 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: bugfix/m5-json-yaml-messages-field-empty-dict
  • Commit Message: fix(output): correct messages field from empty dict to list of {level, text} objects in JSON/YAML envelope
  • Milestone: v3.5.0
  • Parent Epic: #936

Bug Report

Feature Area: CLI output formatting — JSON/YAML envelope structure

Severity: High

Parent Epic: #936 (Output Rendering Pipeline Integration)

Summary

The JsonMaterializer and YamlMaterializer produce a messages field in the output envelope that is an empty dict {} instead of the spec-required list of {level, text} objects. This breaks programmatic consumers that parse the JSON/YAML envelope.

Steps to Reproduce

from cleveragents.cli.output import OutputSession
from cleveragents.cli.output.materializers import JsonMaterializer
import json

strategy = JsonMaterializer()
with OutputSession(format='json', command='test', strategy=strategy) as session:
    status = session.status('All good', level='ok')
    status.close()

output = strategy.get_output()
data = json.loads(output)
print(type(data['messages']))  # <class 'dict'>
print(data['messages'])        # {}

Actual Behavior

{
  "command": "test",
  "status": "ok",
  "exit_code": 0,
  "data": [...],
  "timing": {...},
  "messages": {}
}

The messages field is an empty dict {}.

Expected Behavior

Per the specification (§Output Rendering Framework / JSON envelope):

{
  "command": "version",
  "status": "ok",
  "exit_code": 0,
  "data": {...},
  "timing": { "duration_ms": 8 },
  "messages": [
    { "level": "ok", "text": "Version reported" }
  ]
}

The messages field should be a list of {level, text} objects, where each object corresponds to a StatusMessage element in the session.

Root Cause

In src/cleveragents/cli/output/session.py, the StructuredOutput model defines metadata as dict[str, Any]:

class StructuredOutput(BaseModel):
    metadata: dict[str, Any] = Field(default_factory=dict)

In src/cleveragents/cli/output/materializers.py, _snapshot_to_dict() maps metadata to messages:

result = {
    ...
    "messages": snapshot.metadata,  # BUG: dict, not list
}

Two issues:

  1. StructuredOutput.metadata is a dict, but the spec requires messages to be a list.
  2. StatusMessage elements in the session are serialized into data (as UI elements), not extracted into the messages list.

Fix Required

  1. Change StructuredOutput.metadata to list[dict[str, Any]] (or add a separate messages field).
  2. In _snapshot_to_dict(), extract StatusMessage elements from snapshot.elements and format them as [{"level": ..., "text": ...}] for the messages field.

Code Locations

  • src/cleveragents/cli/output/session.py: StructuredOutput.metadata field type
  • src/cleveragents/cli/output/materializers.py: _snapshot_to_dict() function

Subtasks

  • Change StructuredOutput.metadata type from dict[str, Any] to list[dict[str, Any]] (or introduce a dedicated messages field) in src/cleveragents/cli/output/session.py
  • Update _snapshot_to_dict() in src/cleveragents/cli/output/materializers.py to extract StatusMessage elements from snapshot.elements and serialize them as [{"level": ..., "text": ...}]
  • Verify JsonMaterializer output envelope messages field is a list of {level, text} objects
  • Verify YamlMaterializer output envelope messages field is a list of {level, text} objects
  • Remove @tdd_expected_fail tag from the corresponding TDD test (see TDD issue)
  • Tests (Behave): Confirm all existing scenarios for JSON/YAML envelope pass
  • Tests (Robot): Confirm integration tests for command output structure pass
  • Verify coverage >=97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • The TDD issue (tagged @tdd_issue_<N>) test passes with @tdd_expected_fail removed.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
  • All nox stages pass.
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `bugfix/m5-json-yaml-messages-field-empty-dict` - **Commit Message**: `fix(output): correct messages field from empty dict to list of {level, text} objects in JSON/YAML envelope` - **Milestone**: v3.5.0 - **Parent Epic**: #936 ## Bug Report **Feature Area:** CLI output formatting — JSON/YAML envelope structure **Severity:** High **Parent Epic:** #936 (Output Rendering Pipeline Integration) ### Summary The `JsonMaterializer` and `YamlMaterializer` produce a `messages` field in the output envelope that is an empty dict `{}` instead of the spec-required list of `{level, text}` objects. This breaks programmatic consumers that parse the JSON/YAML envelope. ### Steps to Reproduce ```python from cleveragents.cli.output import OutputSession from cleveragents.cli.output.materializers import JsonMaterializer import json strategy = JsonMaterializer() with OutputSession(format='json', command='test', strategy=strategy) as session: status = session.status('All good', level='ok') status.close() output = strategy.get_output() data = json.loads(output) print(type(data['messages'])) # <class 'dict'> print(data['messages']) # {} ``` ### Actual Behavior ```json { "command": "test", "status": "ok", "exit_code": 0, "data": [...], "timing": {...}, "messages": {} } ``` The `messages` field is an empty dict `{}`. ### Expected Behavior Per the specification (§Output Rendering Framework / JSON envelope): ```json { "command": "version", "status": "ok", "exit_code": 0, "data": {...}, "timing": { "duration_ms": 8 }, "messages": [ { "level": "ok", "text": "Version reported" } ] } ``` The `messages` field should be a **list** of `{level, text}` objects, where each object corresponds to a `StatusMessage` element in the session. ### Root Cause In `src/cleveragents/cli/output/session.py`, the `StructuredOutput` model defines `metadata` as `dict[str, Any]`: ```python class StructuredOutput(BaseModel): metadata: dict[str, Any] = Field(default_factory=dict) ``` In `src/cleveragents/cli/output/materializers.py`, `_snapshot_to_dict()` maps `metadata` to `messages`: ```python result = { ... "messages": snapshot.metadata, # BUG: dict, not list } ``` Two issues: 1. `StructuredOutput.metadata` is a `dict`, but the spec requires `messages` to be a `list`. 2. `StatusMessage` elements in the session are serialized into `data` (as UI elements), not extracted into the `messages` list. ### Fix Required 1. Change `StructuredOutput.metadata` to `list[dict[str, Any]]` (or add a separate `messages` field). 2. In `_snapshot_to_dict()`, extract `StatusMessage` elements from `snapshot.elements` and format them as `[{"level": ..., "text": ...}]` for the `messages` field. ### Code Locations - `src/cleveragents/cli/output/session.py`: `StructuredOutput.metadata` field type - `src/cleveragents/cli/output/materializers.py`: `_snapshot_to_dict()` function ## Subtasks - [ ] Change `StructuredOutput.metadata` type from `dict[str, Any]` to `list[dict[str, Any]]` (or introduce a dedicated `messages` field) in `src/cleveragents/cli/output/session.py` - [ ] Update `_snapshot_to_dict()` in `src/cleveragents/cli/output/materializers.py` to extract `StatusMessage` elements from `snapshot.elements` and serialize them as `[{"level": ..., "text": ...}]` - [ ] Verify `JsonMaterializer` output envelope `messages` field is a list of `{level, text}` objects - [ ] Verify `YamlMaterializer` output envelope `messages` field is a list of `{level, text}` objects - [ ] Remove `@tdd_expected_fail` tag from the corresponding TDD test (see TDD issue) - [ ] Tests (Behave): Confirm all existing scenarios for JSON/YAML envelope pass - [ ] Tests (Robot): Confirm integration tests for command output structure pass - [ ] Verify coverage >=97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - The TDD issue (tagged `@tdd_issue_<N>`) test passes with `@tdd_expected_fail` removed. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. - All nox stages pass. - Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.5.0 milestone 2026-04-03 00:05:46 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: MoSCoW/Should Have — bug or error handling improvement.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: MoSCoW/Should Have — bug or error handling improvement. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveragents-core#1879
No description provided.