fix: find()/stats() correctness + Cortex compat (BR-FIND-WHERE-ZERO, BR-DEFENSIVE-INTERFACE)
Two production correctness defects fixed together so consumers can land
one upgrade.
BR-FIND-WHERE-ZERO — find() returned [] and stats() reported 0 entities
for any workspace whose data was written after the 7.20.0 column-store
refactor. Root cause: getStats() and the getIds() fallback still read
from the deleted sparse-index path. Separately, BaseStorage.getNounType()
was hardcoded to return 'thing', poisoning type-statistics.json with
every noun attributed to that bucket.
- MetadataIndex.getStats() reads from ColumnStore + idMapper.
- MetadataIndex.getIdsFromChunks() throws BrainyError(FIELD_NOT_INDEXED)
when neither store has the field. getIdsForFilter() catches per
clause, logs once, returns [].
- BaseStorage.nounTypeByIdCache populated in saveNounMetadata_internal
and consumed in saveNoun_internal. flushCounts() now persists the
Uint32Array counters too, so readers see fresh per-type counts.
- Self-heal at init: loadTypeStatistics() auto-rebuilds when the
poisoned signature is detected. rebuildTypeCounts() is now public for
use from `brainy inspect repair`.
- Dead state removed: dirtyChunks, dirtySparseIndices,
flushDirtyMetadata().
BR-DEFENSIVE-INTERFACE — 7.21.0 called supportsMultiProcessLocking()
unconditionally, crashing on older Cortex storage adapters that predate
the method. New hasStorageMethod(name) helper gates every new-method
call site. Older adapter triggers a one-line warning at init pointing
at the recommended plugin version.
Tests:
- new tests/integration/find-where-zero.test.ts (7 cases)
- new tests/integration/cortex-compat.test.ts (5 cases)
- multi-process-safety.test.ts updated to enforce correct counts
- 1329/1329 unit + 24/24 new integration tests passing
This commit is contained in:
parent
79f58cb87b
commit
70263113ad
9 changed files with 895 additions and 144 deletions
|
|
@ -3,7 +3,14 @@
|
|||
* Provides better error classification and handling
|
||||
*/
|
||||
|
||||
export type BrainyErrorType = 'TIMEOUT' | 'NETWORK' | 'STORAGE' | 'NOT_FOUND' | 'RETRY_EXHAUSTED' | 'VALIDATION'
|
||||
export type BrainyErrorType =
|
||||
| 'TIMEOUT'
|
||||
| 'NETWORK'
|
||||
| 'STORAGE'
|
||||
| 'NOT_FOUND'
|
||||
| 'RETRY_EXHAUSTED'
|
||||
| 'VALIDATION'
|
||||
| 'FIELD_NOT_INDEXED'
|
||||
|
||||
/**
|
||||
* Custom error class for Brainy operations
|
||||
|
|
@ -99,6 +106,25 @@ export class BrainyError extends Error {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "field is not indexed" error. Thrown by metadata-index reads
|
||||
* when a `where` clause names a field that has neither a column-store
|
||||
* entry nor a sparse-index entry. Callers in `find()` evaluation catch
|
||||
* this, translate the offending clause to an empty result, and log so
|
||||
* the silent-empty behavior is replaced with a loud one. Use
|
||||
* `brain.explain({ where: {...} })` to discover this before running.
|
||||
*/
|
||||
static fieldNotIndexed(field: string): BrainyError {
|
||||
return new BrainyError(
|
||||
`Field "${field}" is not indexed. find()/where will not match any entities. ` +
|
||||
`Likely causes: (1) the writer registered the field in memory but has not flushed; ` +
|
||||
`(2) the field name is mistyped; (3) no entity has ever held this field. ` +
|
||||
`Run brain.explain({ where: { ${field}: ... } }) for the diagnostic.`,
|
||||
'FIELD_NOT_INDEXED',
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a validation error
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue