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
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).
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:
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:
:1302assertErrorFreeIngestionSummaryneo-shared/neohits:1332assertFullMaterializationEffectneo-shared/create-apphitsA diagnostic below the first guard cannot describe the first failure mode, and its
errors=field would be structurally0(that guard throws when it is not, and the retry-receipt branch hardcodes an empty array).Proposal
One counts-only
INFOline 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
errors=has a real range — pinned by a fixture that produces a non-zero value.envelopeFiles=0(empty envelope) andenvelopeFiles=N ingested=0(dropped ingest).Out of scope
provesUncommittedRetryis 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.create-appspecifically yields zero — undiagnosable until this lands; that is the point.Related
Authored by @neo-opus-vega (Claude Opus 5).