mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-28 08:49:38 +02:00
* fix(cli): derive ingest outcomes from saved artifacts * fix(cli): treat artifact-producing ingests with failures as partial * fix(cli): route memory-flow run status through shared ingest outcome * fix(cli): treat partial ingest as saved context in setup status * test(cli): align memory-flow replay expectations with partial ingests
182 lines
5.7 KiB
TypeScript
182 lines
5.7 KiB
TypeScript
import type { MemoryAction } from '../../context/memory/types.js';
|
|
import type { TouchedSlSource } from '../../context/tools/touched-sl-sources.js';
|
|
import type { MemoryFlowReplayInput } from './memory-flow/types.js';
|
|
import type { IngestProvenanceInsert } from './ports.js';
|
|
import type {
|
|
ArtifactResolutionRecord,
|
|
ConflictResolvedRecord,
|
|
EvictionAppliedRecord,
|
|
StageIndex,
|
|
UnmappedFallbackRecord,
|
|
} from './stages/stage-index.types.js';
|
|
import type { WikiSlRefRepair } from './wiki-sl-ref-repair.js';
|
|
import type { IngestDiffSummary, SourceFetchReport, UnresolvedCardInfo } from './types.js';
|
|
|
|
export interface IngestReportWorkUnit {
|
|
unitKey: string;
|
|
rawFiles: string[];
|
|
status: 'success' | 'failed';
|
|
reason?: string;
|
|
actions: MemoryAction[];
|
|
touchedSlSources: TouchedSlSource[];
|
|
slDisallowed?: boolean;
|
|
slDisallowedReason?: 'lookml_connection_mismatch';
|
|
}
|
|
|
|
export interface IngestReportProvenanceDetail {
|
|
rawPath: string;
|
|
artifactKind: 'sl' | 'wiki' | null;
|
|
artifactKey: string | null;
|
|
targetConnectionId?: string | null;
|
|
actionType: IngestProvenanceInsert['actionType'];
|
|
}
|
|
|
|
interface IngestReportToolTranscriptSummary {
|
|
unitKey: string;
|
|
path: string;
|
|
toolCallCount: number;
|
|
errorCount: number;
|
|
toolNames: string[];
|
|
}
|
|
|
|
export interface IngestReportFinalizationMismatch {
|
|
artifactKind: 'sl' | 'wiki';
|
|
key: string;
|
|
direction: 'missing_from_adapter_declaration' | 'extra_in_adapter_declaration';
|
|
}
|
|
|
|
export interface IngestReportFinalizationProvenanceExclusion {
|
|
action: MemoryAction;
|
|
reason: 'missing_raw_paths' | 'raw_path_not_defensible';
|
|
invalidRawPaths?: string[];
|
|
}
|
|
|
|
export interface IngestReportFinalizationOutcome {
|
|
sourceKey: string;
|
|
status: 'success' | 'failed' | 'skipped';
|
|
commitSha: string | null;
|
|
touchedPaths: string[];
|
|
declaredTouchedSources: TouchedSlSource[];
|
|
derivedTouchedSources: TouchedSlSource[];
|
|
declaredChangedWikiPageKeys: string[];
|
|
derivedChangedWikiPageKeys: string[];
|
|
mismatches: IngestReportFinalizationMismatch[];
|
|
result?: unknown;
|
|
errors: string[];
|
|
warnings: string[];
|
|
actions: MemoryAction[];
|
|
provenanceExclusions: IngestReportFinalizationProvenanceExclusion[];
|
|
}
|
|
|
|
interface IngestReportFailure {
|
|
phase: string;
|
|
message: string;
|
|
details?: Record<string, unknown>;
|
|
}
|
|
|
|
export interface IngestReportBody {
|
|
status?: 'completed' | 'failed';
|
|
syncId: string;
|
|
diffSummary: IngestDiffSummary;
|
|
fetch?: SourceFetchReport;
|
|
commitSha: string | null;
|
|
tracePath?: string;
|
|
failure?: IngestReportFailure;
|
|
isolatedDiff?: {
|
|
enabled: boolean;
|
|
integrationWorktreePath?: string;
|
|
ingestionBaseSha?: string;
|
|
projectionSha?: string | null;
|
|
acceptedPatches: number;
|
|
textualConflicts: number;
|
|
semanticConflicts: number;
|
|
resolverAttempts?: number;
|
|
resolverRepairs?: number;
|
|
resolverFailures?: number;
|
|
gateRepairAttempts?: number;
|
|
gateRepairs?: number;
|
|
gateRepairFailures?: number;
|
|
};
|
|
workUnits: IngestReportWorkUnit[];
|
|
failedWorkUnits: string[];
|
|
reconciliationSkipped: boolean;
|
|
// Actions emitted by the reconciliation stage (wiki/sl writes from
|
|
// cross-WU reconciliation). Counted alongside workUnit.actions in
|
|
// savedMemoryCountsForReport so progress reports reflect all writes.
|
|
reconciliationActions?: MemoryAction[];
|
|
conflictsResolved: ConflictResolvedRecord[];
|
|
evictionsApplied: EvictionAppliedRecord[];
|
|
unmappedFallbacks: UnmappedFallbackRecord[];
|
|
artifactResolutions?: ArtifactResolutionRecord[];
|
|
evictionInputs: string[];
|
|
unresolvedCards: UnresolvedCardInfo[];
|
|
supersededBy: string | null;
|
|
overrideOf: string | null;
|
|
provenanceRows: IngestReportProvenanceDetail[];
|
|
toolTranscripts: IngestReportToolTranscriptSummary[];
|
|
finalization?: IngestReportFinalizationOutcome;
|
|
wikiSlRefRepairs?: WikiSlRefRepair[];
|
|
wikiSlRefRepairWarnings?: string[];
|
|
memoryFlow?: MemoryFlowReplayInput;
|
|
}
|
|
|
|
export interface IngestReportSnapshot {
|
|
id: string;
|
|
runId: string;
|
|
jobId: string;
|
|
connectionId: string;
|
|
sourceKey: string;
|
|
body: IngestReportBody;
|
|
createdAt: string;
|
|
}
|
|
|
|
export interface IngestSavedMemoryCounts {
|
|
wikiCount: number;
|
|
slCount: number;
|
|
}
|
|
|
|
export function savedMemoryCountsForReport(report: IngestReportSnapshot): IngestSavedMemoryCounts {
|
|
const workUnitActions = report.body.workUnits.flatMap((workUnit) => workUnit.actions);
|
|
const reconciliationActions = report.body.reconciliationActions ?? [];
|
|
const finalizationActions = report.body.finalization?.actions ?? [];
|
|
const actions = [...workUnitActions, ...reconciliationActions, ...finalizationActions];
|
|
return {
|
|
wikiCount: actions.filter((action) => action.target === 'wiki').length,
|
|
slCount: actions.filter((action) => action.target === 'sl').length,
|
|
};
|
|
}
|
|
|
|
/** @internal */
|
|
export type IngestReportOutcome = 'done' | 'partial' | 'error';
|
|
|
|
export function ingestReportOutcome(report: IngestReportSnapshot): IngestReportOutcome {
|
|
if (report.body.status === 'failed') {
|
|
return 'error';
|
|
}
|
|
if (report.body.failedWorkUnits.length === 0) {
|
|
return 'done';
|
|
}
|
|
const { wikiCount, slCount } = savedMemoryCountsForReport(report);
|
|
return wikiCount + slCount > 0 ? 'partial' : 'error';
|
|
}
|
|
|
|
export function buildStageIndexFromReportBody(jobId: string, connectionId: string, body: IngestReportBody): StageIndex {
|
|
return {
|
|
jobId,
|
|
connectionId,
|
|
workUnits: body.workUnits.map((wu) => ({
|
|
unitKey: wu.unitKey,
|
|
rawFiles: wu.rawFiles,
|
|
status: wu.status,
|
|
reason: wu.reason,
|
|
actions: wu.actions,
|
|
touchedSlSources: wu.touchedSlSources,
|
|
slDisallowed: wu.slDisallowed,
|
|
slDisallowedReason: wu.slDisallowedReason,
|
|
})),
|
|
conflictsResolved: [],
|
|
evictionsApplied: [],
|
|
unmappedFallbacks: [],
|
|
artifactResolutions: body.artifactResolutions ?? [],
|
|
};
|
|
}
|