LearnNewsExamplesServices
Frontmatter
id14109
titleData-integrity diagnostics runner: schedule the detect-producers + route to escalate (#14026 integration)
stateClosed
labels
enhancementaitestingarchitecture
assigneesneo-opus-vega
createdAtJun 26, 2026, 4:31 PM
updatedAtJun 26, 2026, 5:25 PM
githubUrlhttps://github.com/neomjs/neo/issues/14109
authorneo-opus-vega
commentsCount0
parentIssue14026
subIssues
14112 Data-integrity diagnostics runner unit: coverage-wired detect→escalate (#14109 slice 1)
subIssuesCompleted1
subIssuesTotal1
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 26, 2026, 5:25 PM

Data-integrity diagnostics runner: schedule the detect-producers + route to escalate (#14026 integration)

Closed v13.1.0/archive-v13-1-0-chunk-6 enhancementaitestingarchitecture
neo-opus-vega
neo-opus-vega commented on Jun 26, 2026, 4:31 PM

Context

The #14026 detect-signal class now has a family of pure detect-producers — coverage-drift (dataIntegrityCoverageDiagnosis, merged #14075), vector-count monotonicity (#14095), SQLite-integrity (#14096), store-bloat (PR #14103), embedding-dimension (PR #14104) — all the same ({injected inputs}) → recovery-diagnosis | null shape. But every one is an inert pure function: nothing schedules them, gathers their inputs, or routes their diagnoses. The detect-class does not actually detect anything live until this integration lands. This is the #14026 "scheduled wiring" that was explicitly deferred from the producer leaves.

This is the single integration leaf (not N more producer tickets) that closes the full immune-system loop for data-integrity.

The Problem

A diagnostics producer that is never invoked is dead code. The data-integrity dimension that ADR-0025 §2.4 now documents (amendment #14091) and that #13999 proved we need has no live presence: no cadence, no input-gathering, no escalation. The recovery half is useless without the detect half running and reaching it.

The Architectural Reality

The established detect→diagnose→act wiring this plugs into:

  • Detect/diagnose scheduling precedent: ContainerHealthDiagnosisService runs via DeploymentStateBridgeService on a cadence (Orchestrator.mjs:311-316). The data-integrity runner is a sibling — a scheduled service that produces diagnoses from gathered facts.
  • Act/escalate consume (already exists, V-B-A'd): RecoveryActuatorService.escalateDiagnosis (#14061, RecoveryActuatorService.mjs:373) is class/kind-agnostic — it escalates ANY diagnosis whose details.actionClass === 'escalate' (:390), reads targetIdentity, records escalated, pages. The data-integrity diagnoses (recoveryClass: data-integrity, actionClass: escalate, compose-service target) flow through it untouched — confirmed by the live backup-failure escalation (taskOutcomeDiagnosisescalateDiagnosis → page AGENT:*). No actuator change needed.
  • Input sources: auditChromaVectorCoverage (checkChromaIntegrity.mjs:447) for coverage + per-collection counts; store-dir size for bloat; a per-collection embedding-dimension audit + WAL-age sampling (the as-yet-unbuilt audit inputs for the dimension / WAL-age producers).

The Fix

A scheduled data-integrity diagnostics runner (sibling to the container-health diagnosis path) that, on a configurable cadence (ADR-0019 leaf):

  1. Gathers facts — runs auditChromaVectorCoverage, measures store size, audits per-collection dimension + WAL-age; loads the prior sample (persisted) for the monotonicity/growth producers.
  2. Invokes the producers — feeds the gathered facts into each pure producer (buildDataIntegrityCoverageDiagnosis, …Monotonicity…, …StoreBloat…, …DimensionConsistency…, SQLite), collecting the non-null diagnoses.
  3. Routes to the recovery daemon — passes each emitted diagnosis to RecoveryActuatorService.escalateDiagnosis (the existing, generic escalate path) → page. Detect-only; NO auto-repair (data mutation stays operator-gated per ADR-0026).
  4. Persists the current sample as the next run's prior (the history store the monotonicity/growth signals need).

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Data-integrity diagnostics runner (new scheduled service) DeploymentStateBridgeService/ContainerHealthDiagnosisService scheduling precedent Gather facts → invoke producers → route diagnoses to escalateDiagnosis → persist sample A fact-gather failure reports probe-unavailable + skips that signal; never auto-acts service JSDoc + ADR-0025 §2.4 Unit: injected facts → producers fire → escalateDiagnosis invoked; clean facts → no escalation
escalateDiagnosis consume #14061 (RecoveryActuatorService.mjs:390) UNCHANGED — accepts actionClass: escalate data-integrity/compose-service diagnoses as-is n/a V-B-A'd generic; live backup-escalation proof
History/sample persistence monotonicity/growth producers need a prior sample Persist per-run per-collection counts + store-size (deployment-state-adjacent) First run = no prior → those signals no-op (no false escalation) JSDoc Unit: second run compares against first
Cadence + thresholds ADR-0019 SSOT All read at the runner use-site (no parallel readers) config leaves

Decision Record impact

aligned-with ADR-0025 §2.4 (amendment #14091 — the data-integrity detect dimension) + ADR-0026 (escalate-only; no auto-repair). No ADR change — this is the live wiring of the documented model.

Acceptance Criteria

  • A scheduled data-integrity diagnostics runner gathers facts, invokes all available producers, and routes each emitted diagnosis to RecoveryActuatorService.escalateDiagnosis.
  • Detect-only: the runner performs NO repair/re-embed/restore/mutation (escalate-page only).
  • History sample is persisted per run; first run (no prior) does not false-escalate the monotonicity/growth signals.
  • Cadence + thresholds are AiConfig SSOT leaves read at the use-site.
  • A fact-gather failure (probe unavailable) is reported separately and skips that signal — never auto-acts, never crashes the runner.
  • Unit coverage: injected facts → expected producers fire → escalateDiagnosis invoked with the right diagnoses; clean facts → no escalation.

Out of Scope

  • The pure producers themselves (their own leaves — coverage/monotonicity/SQLite/store-bloat/dimension).
  • The as-yet-unbuilt dimension-audit + WAL-age fact-gathering helpers (these may be small sub-slices if non-trivial; the runner consumes them).
  • Any auto-repair / recovery actuator action (escalate-only here; the data-recovery actuator is #14032/#14066 territory, operator-gated).
  • The escalateDiagnosis actuator itself (unchanged — already generic).

Related

  • #14026 (parent detect-signal class — this is its "scheduled wiring" integration leaf), #14075/#14095/#14096/#14103/#14104 (the producers this schedules), #14061 (the escalate sink it routes to), #14091 (the ADR-0025 §2.4 amendment), #14046 (the e2e gate — this is the live counterpart to its in-test scheduled-signal proof), #13999 (the incident the live loop would have caught).

Authored by Vega (Claude Opus 4.8, Claude Code) — #14026 steward; the integration leaf that turns the inert producers into a live immune-system detect→escalate loop. Session c94ea3b2-1ae8-48fd-8f34-1c54d90f5caa.