feat(health): the gate reads the named report — reads refuse loudly, never rebuild; open serves before it returns; the ceremony door
The read gate stops consulting the unnamed isReady() boolean: every provider
may expose healthReport() (sync, O(1), composed from exact ledgers —
HealthReport with a monotonic generation, per-invariant source
ledger|deep|unledgered, missing {count, sample}), and one readiness
authority (assessProviderHealth) derives the verdict. Unledgered families
are UNKNOWN — never healthy, never broken; a report that throws is a loud
not-ready, never a shrug. Reads at the four index choke points refuse with
the typed NotReady errors, narrated once per (provider, generation) — a
read NEVER starts a store walk:
- the first-read lazy build retires (open builds instead, regardless of
size — the ≥10k deferral and the "lazy loading on first query" branch go;
disableAutoRebuild is re-meant honestly in its docs);
- the verify*Live read-path rebuild triggers retire (refuse-or-serve);
- the read-time consistency probe that could launch a dark rebuild from an
ordinary find() retires;
- repairIndex({ rebuild: ['metadata'|'graph'|'vector'] | 'all' }) is the
one explicit door: rebuilds the named leg unconditionally and reports
rebuilt per family; bare repairIndex() stays report-driven.
test(lifecycle): the biography lane — a store's whole life, refereed
tests/lifecycle/: an independent shadow model referees every read after
every chapter (founding, a working day, clean restart, crash, repair,
second life). Chapters 1-3 green. Chapters 4-6 assert the true contract and
are marked .fails as a release-blocking finding (the kill-matrix
convention): after a crash + adopt reopen the metadata index computes its
'catchup' watermark verdict and nothing consumes it — find() serves the
pre-crash index while canonical and counts recover. The catchup wiring is
the cure; a passing .fails will force the marker's removal. The lane runs
in the integration gate (config + coverage guard).
This commit is contained in:
parent
a8b5ca0c8f
commit
f8f64780b1
19 changed files with 2160 additions and 652 deletions
|
|
@ -1831,6 +1831,29 @@ const semanticOnly = await brain.getStats({ excludeVFS: true })
|
|||
|
||||
---
|
||||
|
||||
### `repairIndex(options?)` → `Promise<RepairReport>`
|
||||
|
||||
The ceremony door for index repair. Bare `repairIndex()` is report-driven: it
|
||||
prunes orphaned containers, recomputes count rollups, reconciles VFS
|
||||
containment, and rebuilds only a derived-index family whose own health check
|
||||
asks for it. Pass `options.rebuild` to force one or more families to rebuild
|
||||
UNCONDITIONALLY — no health check is consulted — when an operator has
|
||||
independent reason to reconcile a family regardless of what it self-reports.
|
||||
|
||||
```typescript
|
||||
// Report-driven: only heals what actually needs it
|
||||
const report = await brain.repairIndex()
|
||||
console.log(report.healedTotal, report.families)
|
||||
|
||||
// Explicit: force the graph adjacency to rebuild from canonical, unconditionally
|
||||
await brain.repairIndex({ rebuild: ['graph'] })
|
||||
|
||||
// Explicit: force all three derived indexes to rebuild
|
||||
await brain.repairIndex({ rebuild: 'all' })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Lifecycle
|
||||
|
||||
### Initialization
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue