LearnNewsExamplesServices
Frontmatter
id15201
titleUse toggleCls for single-class AgentOS Fleet markers
stateClosed
labels
enhancementjavascriptairefactoring
assigneesneo-gpt-emmy
createdAtJul 15, 2026, 9:13 PM
updatedAtJul 18, 2026, 5:17 PM
githubUrlhttps://github.com/neomjs/neo/issues/15201
authorneo-gpt-emmy
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 18, 2026, 5:17 PM

Use toggleCls for single-class AgentOS Fleet markers

Closed Backlog/active-chunk-6 enhancementjavascriptairefactoring
neo-gpt-emmy
neo-gpt-emmy commented on Jul 15, 2026, 9:13 PM

Scope Correction — atomicity gate applied

The original six-primitive prescription was falsified before implementation. Sequential removeCls(old) + addCls(new) calls publish two reactive cls changes and an intermediate state carrying neither semantic class. That is the exact stop condition the original ticket named, and D#15200 still has no graduated atomic replace/batch primitive.

This leaf is therefore narrowed to the two Fleet mutations that already map to one public class-API call:

  • StateDot.afterSetLive → enforced toggleCls('fm-live', value)
  • HealthBar.updateAnimateCls → enforced toggleCls('fm-animate-counts', this.animateCounts)

The four old→new replacement hooks (EventChip.afterSetKind, StateDot.afterSetState, HealthSwatch.afterSetState, and FamilyRail.afterSetFamily) remain on their current single aggregate assignment. SourceHealthMarker.applyHealth remains on its coherent set({cls, text}) batch. Their future representation-independent cleanup belongs after D#15200 resolves atomic class replacement; no successor micro-ticket is created now.

The evidence trail is explicit:

Context

Both remaining sites read the aggregate component cls array only to enforce one Boolean class. Neo.component.Base#toggleCls(value, add) already owns that exact boundary in a single reactive assignment, so these two migrations remove representation coupling without changing transition atomicity.

This is an app-only consumer cleanup. It does not define the future cls / wrapperCls representation and introduces no new core API.

The Problem

  • apps/agentos/view/fleet/StateDot.mjs#afterSetLive copies this.cls, adds or removes fm-live, and reassigns the aggregate.
  • apps/agentos/view/fleet/HealthBar.mjs#updateAnimateCls filters this.cls, optionally appends fm-animate-counts, and reassigns the aggregate.

Each intent is a single enforced Boolean membership. Reading unrelated classes is unnecessary.

The Fix

Use the existing enforced toggle form at both sites:

component.toggleCls(className, shouldExist)

Preserve all state, token, Store, motion, and rendering behavior. Do not migrate any old→new replacement or multi-class batch under this ticket.

Decision Record impact

None. The change consumes the existing component API and leaves D#15200 fully open.

Acceptance Criteria

  • StateDot.afterSetLive uses one enforced toggleCls call and no aggregate cls read/reassignment.
  • HealthBar.updateAnimateCls uses one enforced toggleCls call and no aggregate cls read/reassignment.
  • Both true→false and false→true transitions publish exactly one effective cls change when membership changes.
  • Unrelated caller-authored and base classes survive both directions.
  • Repeating the same state is idempotent and creates no duplicate class.
  • Focused unit evidence covers both sites and the one-change invariant.
  • The four old→new replacement hooks and SourceHealthMarker.applyHealth remain unchanged.

Out of Scope

  • EventChip.afterSetKind, StateDot.afterSetState, HealthSwatch.afterSetState, and FamilyRail.afterSetFamily
  • SourceHealthMarker.applyHealth
  • An atomic replaceCls / class transaction primitive
  • D#15200’s object-shaped cls / wrapperCls design
  • Core, VDOM, SCSS, token, visual-design, State Provider, Store, or Model changes
  • Non-AgentOS applications and Workstation

Avoided Traps

  • No sequential remove-then-add for one semantic replacement.
  • No aggregate spread/filter/reassign replacement under another local helper.
  • No silentVdomUpdate or app-local batching seam.
  • No new micro-ticket for the deferred atomicity work.

Related

Origin Session ID: e0413ff9-4738-42b2-9f76-c50690e9edea

Retrieval Hint: "AgentOS Fleet StateDot live HealthBar animateCounts toggleCls single reactive assignment atomicity"