LearnNewsExamplesServices
Frontmatter
id16580
titleA tenant-sync failure states what it materialized, above both guards
stateClosed
labels
enhancementai
assigneesneo-opus-vega
createdAtAug 6, 2026, 8:54 AM
updatedAtAug 6, 2026, 9:26 AM
githubUrlhttps://github.com/neomjs/neo/issues/16580
authorneo-opus-vega
commentsCount0
parentIssue16566
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 6, 2026, 9:26 AM

A tenant-sync failure states what it materialized, above both guards

Closed Backlog/active-chunk-13 enhancementai
neo-opus-vega
neo-opus-vega commented on Aug 6, 2026, 8:54 AM

Problem

When a tenant-repo sync fails, nothing between Refreshing <repo> and the error line says what the run actually did. Measured live: 99 seconds of total silence, then a bare failure code.

That leaves two states with opposite fixes indistinguishable:

what happened fix lives in
the envelope was empty — nothing matched a Source tenant config / source matching
the envelope had files and the ingest materialized none ingestion code

Both currently produce the same silence and the same code. This is what stopped a live diagnosis at "unknown".

There are two guards on this path, and both throw before any success logging:

line guard throws when
:1302 assertErrorFreeIngestionSummary the summary carries any error — the mode neo-shared/neo hits
:1332 assertFullMaterializationEffect zero durable effect — the mode neo-shared/create-app hits

A diagnostic below the first guard cannot describe the first failure mode, and its errors= field would be structurally 0 (that guard throws when it is not, and the retry-receipt branch hardcodes an empty array).

Proposal

One counts-only INFO line emitted above both guards, carrying envelope and ingest counts so the two causes read differently at a glance.

Counts only — no paths, filenames, or repo content. Same credential-boundary discipline that keeps ingestion error messages unprojected: a count cannot carry a clone URL, a token, or stderr.

Acceptance criteria

  • A single line reports envelope file/deleted counts and ingest ingested/deleted/embeddings/errors counts.
  • Emitted above both guards, so it survives an error-bearing summary and a zero-effect materialization alike.
  • errors= has a real range — pinned by a fixture that produces a non-zero value.
  • Both arms of the discrimination are pinned: envelopeFiles=0 (empty envelope) and envelopeFiles=N ingested=0 (dropped ingest).
  • No path, filename, or message projects into the log; asserted directly rather than assumed.
  • No guard weakened; control flow unchanged.

Out of scope

  • The forever-backoff disposition — #16577. A first materialization yielding zero chunks has no prior receipt, so provesUncommittedRetry is structurally false and the repo backs off permanently without ever earning the receipt that would release it. That is a design call about disposition and is deliberately not bundled with a diagnostic.
  • Why create-app specifically yields zero — undiagnosable until this lands; that is the point.
  • The embed-stage failure — #16566.

Related

  • Parent: #16566 — tenant ingestion fails at two different stages.
  • #16577 — the disposition defect this makes diagnosable but does not fix.
  • #16575 / #16576 — multi-cause code reporting; complements this on the failure line.

Authored by @neo-opus-vega (Claude Opus 5).

tobiu referenced in commit 318e6cb - "A materialization states what it materialized, above both guards (#16580) (#16578) on Aug 6, 2026, 9:26 AM
tobiu closed this issue on Aug 6, 2026, 9:26 AM