LearnNewsExamplesServices
Frontmatter
id17329
titleTasks pane: the orchestrator schedule as a first-class cockpit surface
stateClosed
labels
enhancementdesignaiagent-os
assigneesneo-fable-clio
createdAtAug 18, 2026, 10:21 AM
updatedAtAug 22, 2026, 6:47 PM
githubUrlhttps://github.com/neomjs/neo/issues/17329
authorneo-fable-clio
commentsCount1
parentIssue14560
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 22, 2026, 6:47 PM

Tasks pane: the orchestrator schedule as a first-class cockpit surface

Closed Backlog/active-chunk-17 enhancementdesignaiagent-os
neo-fable-clio
neo-fable-clio commented on Aug 18, 2026, 10:21 AM

Tasks pane: the orchestrator schedule as a first-class cockpit surface

Context

Operator, live session 2026-08-18: "a very polished view for the orchestrator scheduler tasks (what is running, % done if possible, next scheduled tasks)." The cockpit's center answers WHO (FleetGrid: agents + state); nothing answers WHAT (work in flight, progress, queue).

The Problem

Mission control without the work axis. The operator reads "0 working · 9 unobserved" but cannot see the running ingestion, the REM backlog, or the next scheduled run. The fleet's memories became a proven surface in the #17271 L1 session; the schedule is the missing operational twin — WHO is only half of mission control.

The Architectural Reality

  • Scheduler substrate exists Brain-side: D#11857 (open) tracks the orchestrator scheduler decomposition; the orchestrator runs as a compose service in ai/deploy/docker-compose.local-agent-os.yml (services: chroma, kb-server, mc-server, orchestrator, fleet-server, ingress).
  • Progress truth exists TODAY for some lanes: KB ingestion progress and MC REM-pipeline state are served by existing plane verbs — the log-proxy pattern (peer-verified 2026-08-13: workload truth answered entirely by proxies).
  • D#16990 (capture-only): our instruments default to binary verdicts and miss "in progress" — this pane is the counter-example by construction: progress IS its subject.
  • Pane siblings: MemoriesPane/CatchUpPane (apps/agentos/view/fleet/) — snapshot-held, intent-firing, cockpit-owned authenticated bridge reads; the Tasks pane follows the same pane contract.

The Fix

A Tasks pane in the south content-tab family (#17269's target model): running tasks (with progress where a truth verb reports it), queued/next-scheduled (with source), recently completed — provenance-labeled per source. Where the orchestrator-schedule verb does not exist yet, the pane renders the honestly-labeled sample state (spine-banner honesty discipline) — it never fakes liveness. The narrowest missing wire verb is named at implementation time as its own service ticket, after D#11857's decomposition settles what serves it.

Contract Ledger Matrix (T3 — added 2026-08-22 at PR #17542 review round 1, RA-3; the diff and its witnesses match this matrix exactly)

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
fleetTasks — NEW read-observe wire verb (ai/services/fleet/fleetWireMethods.mjs, browser twin apps/agentos/config/fleetWireMethods.mjs, FleetControlBridge.fleetTasks) this ticket; fleetServerPolicy.mjs ledgers (awaiting-s3 / read-observe) params reserved ({} today); returns the envelope below; registered on both wire lists and both S1 policy ledgers source not wired → {capability:{state:'unavailable', reason:'fleet tasks source not wired'}, viewer:null, sources:{}, running:[], queued:[], recent:[], counts:{0,0,0}} verb JSDoc dispatchFleetRequest.spec allowlist, fleetServer.spec ledgers, ai:lint-fleet-vocabulary-parity
Identity binding RequestContextService.getAgentIdentityNodeId() through the injected resolveViewerIdentity, resolved INSIDE every readTasks() call (the memories-source posture) the envelope stamps the server-resolved viewer; every producer operation receives {} — no caller identity claim ever rides the operation non-canonical viewer → throws authenticated ingress did not bind a canonical viewer identity → dispatcher operationFailed → cockpit fallback fleet tasks read failed (never a defaulted identity) source JSDoc fleetTasksSource.spec "refused, never defaulted"
Envelope {capability:{state, capturedAt, reason?}, viewer, sources:{deployment, rem, ingestion}, running[], queued[], recent[], counts} this ticket fold: wired = every WIRED axis answered (wired, stale or degraded — the reader's retained-snapshot statuses still measure, matching ANSWERED_STATES in the source); partial = some answered; unavailable = none (reason:'no-task-source-answered'); an unwired axis never degrades the fold each sources.<axis> carries {state, reason, detail?} (+ observedAt for deployment, scope for ingestion) source JSDoc fleetTasksSource.spec fold cases (wired / unwired-does-not-degrade / partial / unavailable)
Row {id, section, name, source, state, at, progress: {kind:'determinate'|'backlog', done, total}|null, detail} this ticket; AgentOS.model.FleetTask converts (unknown section/source → null) running + recent newest-first, queued soonest-first, instant-less rows last; 12 rows per section; progress only when both counts are real and total > 0 model + source JSDoc source ordering/cap specs, tasksPane.spec
Producer — deployment snapshot: get_deployment_state_snapshotreadDeploymentStateSnapshot() (ai/services/memory-core/helpers/deploymentStateBridgeStore.mjs) that reader's envelope contract: {ok:true, status:'available', snapshot} · {ok:false, status:'stale', snapshot, reason:'snapshot-stale'} · {ok:false, status:'degraded', snapshot, reason} (both RETAIN the snapshot) · {ok:false, status:'unavailable', snapshot:null, reason} available → axis wired, rows from tenantRepoSync.task (running / last completion), tenantRepoSync.repos[] (one queued row per enabled repo with nextDueAt; due → word due; corpusOutstanding → backlog gauge), maintenance.retry (queued under its phase), recoveryRuns.entries[] (in flight → running, finished → recent), selfHeal.summary.currentlyFrozen[] (running, word frozen); stale → axis stale, rows retained; tenant/repo identifiers never leave the reducer (identity-hash labels only) other ok:false → axis unavailable with the producer reason; thrown read → deployment-read-failed + redacted detail; completion time: completedlastSuccessAt ?? lastRunAt, failedlastErrorAt ?? lastRunAt, skippedlastRunAt source JSDoc live-shaped fixture; the REAL stale shape; failed + skipped completion witnesses; tenant-identifier leak witness
Producer — REM: get_rem_pipeline_stateHealthService.buildRemPipelineState() (ai/services/memory-core/HealthService.mjs:859-900, OpenAPI openapi.yaml) {undigested, digested, sessionNodes, topologyConflicts, recentCycles[{runId, wallClockMs, cycleOverflowSignal, cycleOverflowRatio, outcome}], axisErrors?} — cycles carry NO instant and no active flag; a failed axis read records axisErrors.<axis> and falls back to 0 exactly ONE queued row mc:rem:digest, word backlog, gauge digested / (digested + undigested), at: null; the latest cycle's outcome rides the detail; never a running claim axisErrors.undigested or .digested → axis unavailable (rem-axis-error) — fallback zeroes never become a wired measurement; unrecognized payload → rem-payload-unrecognized source JSDoc producer-shaped fixtures; axisErrors red control
Producer — KB ingestion: get_ingestion_progressIngestionService.getIngestionProgress() (ai/services/knowledge-base/IngestionService.mjs:831, observedScope: this-process-only) that producer's {status, active, phase, stalled, startedAt, completedAt, totalChunks, embeddedChunks, errorCount, lastRunSummary, observedScope} bound in IN-PROCESS mode only (the plane client proves identity against the Memory Core plane and holds no Knowledge Base session); active → running row, determinate embeddedChunks/totalChunks, stalled → word stalled; idle → recent row from lastRunSummary; tenantId / repoSlug never rendered plane mode → axis unwired (ingestion-verb-unreachable-from-this-process), no degrade; thrown → ingestion-read-failed; unrecognized → ingestion-payload-unrecognized source + wiring JSDoc source spec (active / stalled / idle / leak)
Bounds + redaction redactReadFailure / redactCredentials (the fleet's single redaction authority); MAX_ROWS = 12 the ~100 KB snapshot never crosses the wire; every thrown-read detail passes the redactor before it is bounded source JSDoc "a throwing axis carries a redacted detail" witness
Consumer — FleetCockpit.loadTasks (boot, liveness tick with its own in-flight cap, reconnect) → TasksPane (AgentOS.store.FleetTasks projection) the sibling loaders' three laws (#16415 write-time resolution) typed unavailable for an unwired/throwing bridge; generation fence; pane resolved at WRITE time through getTasksPane() (docked / vesseled / returning) transport-cold (no source axes) → the labeled sample stays (Activity-stream convention); source-cold → honest empty lines under the reason cockpit + pane JSDoc fleetCockpit.spec loadTasks block, tasksPane.spec, FleetTasksPaneNL journey through the authenticated loopback transport

Acceptance Criteria

  • Design sketch (§04-consistent) reviewed BEFORE implementation (spec-first gate).
  • Pane renders running (with %-progress where the wire reports it), queued/next-scheduled (with source), completed-recent — each row provenance-labeled (live verb vs sample).
  • Existing truth verbs bound where available (ingestion progress, REM state) through the authenticated bridge; absent sources render as absence, never invented rows.
  • In-shell + pop-out parity per the established childapp widget-route pattern.
  • Zero CSS-in-JS; tokens only; both themes.

Out of Scope

The orchestrator-schedule wire verb (named follow-up once D#11857 settles the serving shape) · acting on tasks (cancel/re-run — operator actuation is its own security surface) · the other panes' content design (#17268).

Related

Epic #14560 (parent) · #17269 (south-tab placement) · D#11857 (scheduler substrate decomposition) · D#16990 (the missing third state) · #17271 (the L1 surface precedent).

Live latest-open sweep: latest 20 re-checked 2026-08-18T08:15Z, no equivalent; A2A herd window clean (one unrelated engine claim #17327).

Origin Session ID: ca3c67ac-a3d6-4e93-98e0-c5f7f65011ee

Retrieval Hint: query_raw_memories("tasks pane orchestrator schedule progress running queued cockpit south tab")