LearnNewsExamplesServices
Frontmatter
id14064
titleConsume supervised-task diagnosis helper in backup escalation
stateClosed
labels
enhancementaitestingarchitecture
assigneesneo-opus-vega
createdAtJun 26, 2026, 7:16 AM
updatedAtJun 26, 2026, 7:33 PM
githubUrlhttps://github.com/neomjs/neo/issues/14064
authorneo-gpt
commentsCount1
parentIssue14039
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 14055 #14030 AC1 producer-core: supervised-task failure/overdue diagnosis helpers
blocking[]
closedAtJun 26, 2026, 7:33 PM

Consume supervised-task diagnosis helper in backup escalation

Closed v13.1.0/archive-v13-1-0-chunk-6 enhancementaitestingarchitecture
neo-gpt
neo-gpt commented on Jun 26, 2026, 7:16 AM

Context

PR #14061 delivered the #14058 backup failure diagnosis escalation hook+sink and is approved. Vega's review intentionally left a follow-up instead of blocking the PR: ProcessSupervisorService.escalateFailedTaskOutcome() currently builds the recovery-diagnosis inline because PR #14056's buildSupervisedTaskDiagnosis helper is approved but not merged. Importing that helper directly in #14061 would have stacked the PR, which is forbidden for this lane.

Vega and @neo-gpt converged on the semantic class: a failed maintenance task should route as recoveryClass: 'ambiguous', not crash, because the supervisor observed the failure but not its cause. Vega owns aligning the helper after #14056 merges; this ticket owns consuming that helper from the backup escalation path afterward.

Live latest-open sweep: checked latest 30 open issues at 2026-06-26T05:15Z. Closest tickets were #14058 (delivered hook+sink), #14055/#14056 (producer helper), and #14030 (parent backup reliability), but no equivalent post-merge helper-consumption follow-up existed. Targeted GitHub search backup escalation supervised-task diagnosis helper #14056 #14061 returned no open issue. A2A in-flight sweep over the latest 30 messages found Vega's #14061 approval/follow-up and my agreement, but no competing claim. KB/local keyword sweeps found no duplicate for escalateFailedTaskOutcome / buildSupervisedTaskDiagnosis.

The Problem

Leaving the inline diagnosis build in ProcessSupervisorService after #14056 lands would create two producer paths for the same supervised-task failure diagnosis contract. That is exactly the class of drift the producer-core split was meant to avoid: one helper says what a supervised-task failure diagnosis means, while the backup escalation path silently carries a local variant.

There are two small documentation polish points from the same review loop that should travel with this refactor instead of being remembered only in A2A:

  1. RecoveryActuatorService.escalateDiagnosis() now has observable return statuses (escalated, rejected variants) consumed by tests/operators; the return-shape contract should be captured in the ticket/contract ledger surface.
  2. Orchestrator now has a bidirectional ProcessSupervisorService <-> RecoveryActuatorService setter cross-link; a one-line comment should explain that this is service graph reconciliation, not arbitrary circular wiring.

The Architectural Reality

  • #14061 intentionally built the diagnosis inline to avoid stacking on unmerged PR #14056.
  • #14056 owns the shared producer helper for supervised-task failure/overdue diagnosis events.
  • The agreed maintenance-task failure class is ambiguous: the failed task needs escalation, not an automatic crash-recovery action.
  • RecoveryActuatorService.escalateDiagnosis() is an alarm-only sink. It must keep rejecting non-escalate diagnosis events and must not execute target actions.
  • Orchestrator wires services reactively; the new cross-link keeps the supervisor able to call the actuator sink while the actuator still knows about the supervisor for ordinary recovery actions.

The Fix

After #14056 is merged and its helper has the agreed failed -> ambiguous behavior:

  1. Refactor ProcessSupervisorService.escalateFailedTaskOutcome() to consume the shared supervised-task diagnosis producer instead of constructing the diagnosis inline.
  2. Preserve #14061 behavior: failed backup outcomes escalate once, use targetIdentity: {kind: 'supervised-task', id: 'backup'}, and never call privileged target actions.
  3. Add or update focused unit coverage proving the helper-generated failed-backup diagnosis still routes as ambiguous and preserves the maintenance-task-failure reason/details.
  4. Add a concise comment to the Orchestrator service setter cross-link explaining the bidirectional service graph reconciliation.
  5. Backfill the return-shape Contract Ledger for RecoveryActuatorService.escalateDiagnosis() on the #14058/#14061 follow-up surface, including escalated, invalid-diagnosis, and diagnosis-not-escalatable outcomes.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
ProcessSupervisorService.escalateFailedTaskOutcome() diagnosis producer #14056 producer-core helper + #14061 approved hook+sink Use the shared helper for failed backup supervised-task diagnoses once available Keep inline build only until #14056 lands Method JSDoc / review follow-up ticket Unit test asserts helper-compatible ambiguous classification and sink call
RecoveryActuatorService.escalateDiagnosis() return shape #14058 Contract Ledger + #14061 implementation Document returned statuses and rejection reason codes as consumed contract Existing JSDoc remains source until ledger backfill lands Contract Ledger matrix / JSDoc Unit tests assert escalated and rejected statuses
Orchestrator supervisor/actuator cross-link Runtime service graph wiring in #14061 Add one-line source comment explaining why both services receive each other through setter reconciliation No behavior change Inline code comment Source preflight / focused unit suite

Decision Record impact

Aligned with ADR-0025 / ADR-0026: single producer contract for diagnosis events, alarm-only escalation for ambiguous maintenance failures, and bounded recovery action. No ADR amendment required.

Acceptance Criteria

  • ProcessSupervisorService.escalateFailedTaskOutcome() consumes the shared supervised-task diagnosis helper after #14056 is available.
  • Failed backup task escalation still produces recoveryClass: 'ambiguous', reasonCode: 'maintenance-task-failure', and targetIdentity.kind: 'supervised-task'.
  • Existing no-privileged-action guarantees from #14061 remain covered by focused unit tests.
  • RecoveryActuatorService.escalateDiagnosis() return statuses are captured in a Contract Ledger/JSDoc surface.
  • The Orchestrator bidirectional service wiring has a concise explanatory comment.

Out of Scope

  • Reworking #14061's approved alarm-only sink.
  • Changing #14056 before it lands; Vega owns the helper alignment lane.
  • Adding scheduling-overdue detection; that remains Vega's AC1 piece-3 after #14056 merges.
  • Restarting or retrying backup automatically.

Avoided Traps

  • Do not import from an unmerged PR or stack a non-dev branch.
  • Do not classify generic maintenance-task failure as crash without causal evidence.
  • Do not turn the helper refactor into a second escalation design cycle; preserve #14061 behavior.

Related

Refs #14039

Related: #14056, #14058, #14061, #14030, #14055

BLOCKED_BY #14056

Origin Session ID: 35f83031-f1a6-41a7-9c3b-089b87307db9

Handoff Retrieval Hints: query_raw_memories("#14061 approved follow-up buildSupervisedTaskDiagnosis ambiguous backup escalation"); A2A anchors: MESSAGE:472f2a10-82e3-4b74-b224-fab140aa0174, MESSAGE:4ebd5c85-4708-468e-9bd1-22ed23761ce6; source anchors: ProcessSupervisorService.escalateFailedTaskOutcome, RecoveryActuatorService.escalateDiagnosis, Orchestrator.afterSetProcessSupervisorService.

tobiu unassigned from @neo-gpt on Jun 26, 2026, 3:55 PM