LearnNewsExamplesServices
Frontmatter
id17625
titleThe Mailbox tab witness resolves a class that two surfaces share, and asserts against the wrong instance
stateClosed
labels
bugaitesting
assignees[]
createdAtAug 23, 2026, 6:52 PM
updatedAtAug 23, 2026, 7:38 PM
githubUrlhttps://github.com/neomjs/neo/issues/17625
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 23, 2026, 7:38 PM

The Mailbox tab witness resolves a class that two surfaces share, and asserts against the wrong instance

Closed Backlog/active-chunk-19 bugaitesting
neo-opus-grace
neo-opus-grace commented on Aug 23, 2026, 6:52 PM

Context

Carved from #17596 rows 4–5, following that ticket's own pattern of moving a shared cause to its own leaf (#17598 precedent) so the fix carries an honest close target rather than waiting on the other fourteen rows.

#17596's body records these rows as "the specs are correct and are reporting a real product defect." That is wrong — my own sentence, corrected there (comment). The possession hand-off works. The witness is holding the wrong object.

The Problem

test/playwright/e2e/agentos/FleetMailboxTabNL.spec.mjs:75 resolves the pane by class alone and takes the first match:

const [mounted] = await app.queryComponent({className: 'AgentOS.view.fleet.mailbox.Container'}, ['record', 'snapshot', 'id']);
expect(mounted?.properties?.record?.agentId, 'the pane record follows the drill').toBe(expectedAgentId);

Measured during the drill on dev at 2026-08-23T16:51Z, that query returns two instances:

id                        agentId          mounted   parentId
neo-fm-mailbox-pane-1     null             false     neo-fm-operator-mailbox-1
neo-fm-mailbox-pane-2     neo-opus-ada     true      neo-container-103

Neither is an orphan, which was checked before concluding — a leaked instance and two legitimate instances are different defects with opposite owners:

  • pane-1 belongs to the Operator Mailbox (neo-fm-operator-mailbox-1), a different feature surface, and is not mounted. It correctly holds no drilled record because it is not the AgentDetail tab.
  • pane-2 is the AgentDetail Mailbox tab, mounted, holding exactly the record the drill selected.

AgentOS.view.fleet.mailbox.Container is used by two surfaces. The spec assumes the class identifies one.

Row 5 (:202) is the same seam, not a second defect. After that query the spec injects its snapshot into mounted.properties.id — i.e. into pane-1, the unmounted Operator Mailbox pane. The rows therefore never render in the AgentDetail tab and toHaveCount(50) receives 0. #17596 predicted one seam for both rows and was right about that; only the owner was wrong.

The Architectural Reality

  • test/playwright/e2e/agentos/FleetMailboxTabNL.spec.mjs:75 — the className-only resolution, and :~90 — the injection that inherits it.
  • AgentOS.view.fleet.mailbox.Container — shared by the AgentDetail Mailbox tab and the Operator Mailbox.
  • The query surface (queryComponent) returns every match; ordering across two independently-created instances is not a contract the spec may lean on.

A className query is only an identity when the class is unique. This one stopped being unique and nothing told the spec, because a first-match query has no failure mode — it silently returns something.

The Fix

Resolve the AgentDetail tab's pane specifically rather than by bare class. Cheapest ordering:

  1. Filter on mounted === true — the Operator Mailbox instance is unmounted during this journey.
  2. Or scope through the AgentDetail pane / its known parent, which states the intent rather than a property that happens to discriminate today.

Option 2 is preferred if the parent is reachable: mounted is a symptom of being the right pane, not a definition, and a future journey that mounts both would silently re-break option 1.

Acceptance Criteria

  • FleetMailboxTabNL:23 and :202 pass on dev, and the pane they assert against is the AgentDetail tab's instance, established by identity rather than by list position.
  • A control proves the disambiguation is load-bearing: the spec must fail if it resolves the Operator Mailbox instance. Asserting the resolved pane's parentId/identity is enough — without it the fix is indistinguishable from the ordering having changed in our favour.
  • The resolution does not depend on queryComponent ordering, asserted by intent rather than by the value that happens to sort first.
  • No production change. If the fix appears to need one, that finding supersedes this ticket and belongs back on #17596.
  • The corrected classification lands in #17596's row table so the next reader does not re-inherit "real product defect".

Out of Scope

  • The other fifteen #17596 rows. Unclassified there on purpose; a confident guess is worse than the gap.
  • The DemoB* cluster — read against #17578 first.
  • Visual-baseline (toHaveScreenshot) failures — excluded by #17596.
  • Adding e2e to CI#17596 notes it as a separate decision, and this leaf does not change that argument.
  • Renaming or splitting mailbox.Container. Two surfaces sharing a component is legitimate; the spec's assumption is the defect.

Avoided Traps

  • Calling it a product defect from the error text. Received: undefined reads identically whether the product failed to populate an instance or the witness is holding the wrong one. Two readers (myself and @neo-gpt) classified it from failure text and both landed on the wrong owner — the instance census is what separated them.
  • Assuming the second instance is a leak. It is a legitimately-mounted-elsewhere Operator Mailbox pane; "fixing" it by destroying it would break that surface.
  • Fixing by mounted alone without saying why. It discriminates today because one pane happens to be unmounted. That is a coincidence the spec would be relying on, so the AC asks for identity.

Related

#17596 (parent census, and the corrected classification) · #17598 / PR #17599 (the carve precedent) · #17593 (the selection PR that moved the surface after the census, changing the expected agent from neo-gemini-pro to neo-opus-ada while the failure shape held)

Live latest-open sweep: latest 12 open read at 2026-08-23T16:52:13Z plus a state:all search for mailbox/pane/instance-query scope — nearest are #17596 (the parent) and #17560 (CLOSED, unrelated folder topology). No equivalent. A2A in-flight claim sweep: 12 most recent messages, window 16:08–16:47Z; active claims are #17419 (@neo-gpt-emmy), #17377/#17621 (@neo-preview); none overlap.

Origin Session ID: eb671e6e-ca17-4a53-8069-64fd5885ce84

Retrieval Hint: FleetMailboxTabNL agentId undefined; two mailbox.Container instances neo-fm-mailbox-pane-1 unmounted Operator Mailbox vs pane-2 AgentDetail tab; className-only queryComponent first match; snapshot injected into wrong pane so toHaveCount 0

tobiu referenced in commit 6ade148 - "fix(test): the Mailbox tab witness resolves its own pane by identity (#17625) (#17628) on Aug 23, 2026, 7:38 PM
tobiu closed this issue on Aug 23, 2026, 7:38 PM