chore(8.0): final pre-RC1 sweep — API consistency, named errors, orphans, zero-cast codebase

This commit is contained in:
David Snelling 2026-06-11 14:51:00 -07:00
parent 970e08c466
commit 1f7e365a4e
237 changed files with 1951 additions and 49413 deletions

View file

@ -123,7 +123,7 @@ export class BackgroundDeduplicator {
try {
// Get all entities from this import using brain.find()
const results = await this.brain.find({
where: { importId } as any,
where: { importId },
limit: 100000 // Large limit to get all entities from import
})
@ -298,7 +298,7 @@ export class BackgroundDeduplicator {
return this.brain.find({
query,
limit: 5,
where: { type: entity.type } as any // Type-aware search
where: { type: entity.type } // Type-aware search
})
})
@ -318,8 +318,11 @@ export class BackgroundDeduplicator {
// Check if not already merged
const stillExists = await this.brain.get(entity.id)
if (stillExists) {
// Cast match.entity to HNSWNounWithMetadata (it comes from brain.find results)
const matchEntity = match.entity as any as HNSWNounWithMetadata
// Typed boundary: bridge the public Entity<T> result shape from
// brain.find() to the storage-layer HNSWNounWithMetadata record
// (same structural bridge as the results.map above). The merge
// path only reads id/type/metadata, present in both shapes.
const matchEntity = match.entity as unknown as HNSWNounWithMetadata
await this.mergeEntities([entity, matchEntity], 'Similarity')
merged++
break // Only merge with first high-similarity match
@ -388,7 +391,7 @@ export class BackgroundDeduplicator {
for (const entity of entities) {
if (entity.id !== primary.id) {
try {
await this.brain.delete(entity.id)
await this.brain.remove(entity.id)
} catch (error) {
// Entity might already be deleted, continue
prodLog.debug(`[BackgroundDedup] Could not delete ${entity.id}:`, error)

View file

@ -88,7 +88,7 @@ export class EntityDeduplicator {
const results = await this.brain.find({
query: searchText,
limit: 5,
where: opts.strictTypeMatching ? { type: candidate.type } as any : undefined
where: opts.strictTypeMatching ? { type: candidate.type } : undefined
})
// Check each result for potential duplicates
@ -227,7 +227,9 @@ export class EntityDeduplicator {
const entityId = await this.brain.add({
data: candidate.description || candidate.name,
type: candidate.type,
subtype: (candidate as any).subtype ?? 'imported',
subtype:
(candidate as EntityCandidate & { subtype?: string }).subtype ??
'imported',
confidence: candidate.confidence,
metadata: {
...candidate.metadata,

View file

@ -12,7 +12,7 @@
import { Brainy } from '../brainy.js'
import { FormatDetector, SupportedFormat } from './FormatDetector.js'
import { ImportHistory } from './ImportHistory.js'
import { ImportHistory, type ImportHistoryEntry } from './ImportHistory.js'
import { BackgroundDeduplicator } from './BackgroundDeduplicator.js'
import { SmartExcelImporter } from '../importers/SmartExcelImporter.js'
import { SmartPDFImporter } from '../importers/SmartPDFImporter.js'
@ -489,7 +489,13 @@ export class ImportCoordinator {
await this.history.recordImport(
importId,
{
type: normalizedSource.type === 'path' ? 'file' : normalizedSource.type as any,
// 'url' sources were already converted to 'buffer' by
// normalizeSource() → fetchUrl(), so only history-recordable
// source types remain here after the 'path' → 'file' mapping.
type:
normalizedSource.type === 'path'
? 'file'
: (normalizedSource.type as ImportHistoryEntry['source']['type']),
filename: normalizedSource.filename,
format: detection.format
},
@ -699,11 +705,25 @@ export class ImportCoordinator {
format: SupportedFormat,
options: ImportOptions
): Promise<any> {
// Check if IntelligentImportAugmentation already extracted data
if ((options as any)._intelligentImport && (options as any)._extractedData) {
const extractedData = (options as any)._extractedData
// Check if IntelligentImportAugmentation already extracted data.
// Typed boundary: the intelligent-import pre-processing path smuggles its
// results onto ImportOptions via these underscore-prefixed private fields —
// they are not part of the public ImportOptions contract.
const intelligentOptions = options as ImportOptions & {
_intelligentImport?: boolean
_extractedData?: Array<{
id?: string
name?: string
type?: string
description?: string
metadata?: Record<string, unknown>
}>
_metadata?: { intelligentImport?: Record<string, unknown> }
}
if (intelligentOptions._intelligentImport && intelligentOptions._extractedData) {
const extractedData = intelligentOptions._extractedData
// Convert extracted data to ExtractedRow format
const rows = extractedData.map((item: any) => ({
const rows = extractedData.map((item) => ({
entity: {
id: item.id || `entity-${Date.now()}-${Math.random()}`,
name: item.name || item.type || 'Unnamed',
@ -719,7 +739,7 @@ export class ImportCoordinator {
rows,
entities: extractedData,
relationships: [],
metadata: (options as any)._metadata?.intelligentImport || {},
metadata: intelligentOptions._metadata?.intelligentImport || {},
stats: {
byType: {},
byConfidence: {}
@ -811,7 +831,7 @@ export class ImportCoordinator {
entity: {
id: imageId,
name: imageName,
type: 'media' as any,
type: 'media',
description: '',
confidence: 1.0,
metadata: { subtype: 'image' }
@ -864,7 +884,18 @@ export class ImportCoordinator {
provenanceCount?: number
}> {
const entities: Array<{ id: string; name: string; type: NounType; vfsPath?: string; metadata?: Record<string, any> }> = []
const relationships: Array<{ id: string; from: string; to: string; type: VerbType }> = []
// Wider than the declared return type: confidence/weight/metadata are
// collected per relationship for the relateMany() batch below; callers of
// createGraphEntities() only see the narrower {id, from, to, type} rows.
const relationships: Array<{
id: string
from: string
to: string
type: VerbType
confidence?: number
weight?: number
metadata?: { evidence?: string; [key: string]: unknown }
}> = []
let mergedCount = 0
let newCount = 0
@ -1227,7 +1258,7 @@ export class ImportCoordinator {
...trackingContext.customMetadata
})
}
} as any)
})
} catch (error) {
// Skip relationship collection errors (entity might not exist, etc.)
continue
@ -1314,7 +1345,7 @@ export class ImportCoordinator {
verbType = this.inferRelationshipType(
sourceEntity.type,
targetEntity.type,
(rel as any).metadata?.evidence
rel.metadata?.evidence
)
}
@ -1323,7 +1354,7 @@ export class ImportCoordinator {
to: rel.to,
type: verbType, // Enhanced type
metadata: {
...((rel as any).metadata || {}),
...(rel.metadata || {}),
relationshipType: 'semantic', // Distinguish from VFS/provenance
inferredType: verbType !== rel.type, // Track if type was enhanced
originalType: rel.type

View file

@ -165,7 +165,7 @@ export class ImportHistory {
// Delete entities
for (const entityId of entry.entities) {
try {
await this.brain.delete(entityId)
await this.brain.remove(entityId)
result.entitiesDeleted++
} catch (error) {
result.errors.push(`Failed to delete entity ${entityId}: ${error instanceof Error ? error.message : String(error)}`)