Skip to content

pm list silently drops unreadable items from items[]/count and reports has_more:false, so agents consume a filtered workspace as complete #752

Description

@unbraind

Summary

When an item document fails to decode, pm list omits it from items[] and from count, reporting the loss only as a string in warnings[]. An agent consuming pm list --json therefore receives a well-formed, plausible, silently incomplete result set. Nothing in the shape of the response distinguishes "3 open items" from "3 open items, and 2 more I could not read".

For a tool whose premise is that project management is context management, silently narrowing an agent's view of the workspace is the most damaging possible failure mode: the agent does not know to distrust the answer.

Reproduction

Any unreadable item reproduces it. A drifted @toon-format/toon install (see #747) is one easy way:

$ pm list --json
{
  "items": [ ... 2 items ... ],
  "count": 2,
  "total": 2,
  "has_more": false,
  "truncated": false,
  "warnings": [
    "item_list_item_read_failed:chores/pm-gantt-chart-xcqd.toon",
    "item_list_item_read_failed:issues/pm-gantt-chart-76at.toon"
  ]
}

count, total, has_more: false and truncated: false all assert completeness. Two of the four items in the workspace are simply gone.

Why this cost real time

Diagnosing this took hours across a 20-workspace fleet, because every symptom pointed at data corruption rather than at the environment:

  • pm list looked successful — correct exit code, no error, a coherent item set.
  • pm get <id> failed with TOON item document is not valid TOON, which reads as "this document is malformed" and says nothing about the decoder.
  • pm validate did flag validate_storage_unreadable_items, which is good, but by then the natural conclusion was that committed items had been corrupted.

The actual cause was that @unbrained/pm-cli correctly declares "@toon-format/toon": "^2.3.1" while the resolved package on disk was 2.3.0 — a version whose decoder rejects bracketed segments inside quoted scalars. The lockfiles pinned 2.3.1; npm install reported up to date without reconciling the drift. 29 items across 13 workspaces were invisible, and every one was byte-identical to its committed version.

Requests

1. Never report a filtered result set as complete. When reads fail, either surface the loss structurally so a consumer must see it:

{
  "items": [...],
  "count": 2,
  "unreadable_count": 2,
  "unreadable": ["chores/pm-gantt-chart-xcqd.toon", "issues/pm-gantt-chart-76at.toon"],
  "complete": false
}

…or fail the command outright under a strict flag. A warnings[] string is easy for a programmatic consumer to ignore, and agents do ignore it. complete: false (or a non-zero unreadable_count) is not ignorable by an agent that checks its own result shape.

2. Name the decoder version in the decode error. TOON item document is not valid TOON attributes the fault to the document. When the installed @toon-format/toon does not satisfy pm's own declared range, say so:

TOON item document is not valid TOON
Why: the installed @toon-format/toon is 2.3.0, but this pm build requires >=2.3.1.
     2.3.0 cannot decode bracketed segments inside quoted scalars.
Recovery: rm -rf node_modules/@toon-format/toon && npm install

That single line would have replaced the entire investigation.

3. Consider a startup guard. A cheap runtime check that the resolved decoder satisfies the declared range, failing loudly once at startup, converts a silent whole-workspace integrity failure into an unmissable one-line diagnosis.

Environment

  • @unbrained/pm-cli 2026.7.26
  • resolved @toon-format/toon 2.3.0 (declared ^2.3.1, lockfile pinned 2.3.1)
  • Node 26.5.0, Linux

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions