feat(ingest): report isolated diff resolver outcomes

This commit is contained in:
Andrey Avtomonov 2026-05-18 00:24:12 +02:00
parent 8784a47f84
commit aa8d59c14a
4 changed files with 79 additions and 0 deletions

View file

@ -15,6 +15,7 @@ import { validateFinalIngestArtifacts, validateProvenanceRawPaths } from './arti
import { selectRelevantCanonicalPins } from './canonical-pins.js';
import { FileIngestTraceWriter, ingestTracePathForJob, type IngestTraceWriter, traceTimed } from './ingest-trace.js';
import { integrateWorkUnitPatch } from './isolated-diff/patch-integrator.js';
import { resolveTextualConflict } from './isolated-diff/textual-conflict-resolver.js';
import { runIsolatedWorkUnit } from './isolated-diff/work-unit-executor.js';
import { sanitizeMemoryFlowError } from './memory-flow/live-buffer.js';
import type { CanonicalPin } from './canonical-pins.js';
@ -965,6 +966,9 @@ export class IngestBundleRunner {
acceptedPatches: number;
textualConflicts: number;
semanticConflicts: number;
resolverAttempts: number;
resolverRepairs: number;
resolverFailures: number;
}
| undefined;
await trace.event('info', 'run', 'ingest_started', {
@ -1286,6 +1290,9 @@ export class IngestBundleRunner {
acceptedPatches: 0,
textualConflicts: 0,
semanticConflicts: 0,
resolverAttempts: 0,
resolverRepairs: 0,
resolverFailures: 0,
};
latestIsolatedDiffSummary = isolatedDiffSummary;
@ -1521,7 +1528,28 @@ export class IngestBundleRunner {
),
});
},
resolveTextualConflict: (context) =>
resolveTextualConflict({
agentRunner: this.deps.agentRunner,
workdir: sessionWorktree.workdir,
unitKey: context.unitKey,
patchPath: context.patchPath,
touchedPaths: context.touchedPaths,
trace: runTrace,
reason: context.reason,
maxAttempts: 1,
stepBudget: 12,
}),
});
if (integration.textualResolution) {
isolatedDiffSummary.resolverAttempts += integration.textualResolution.attempts;
if (integration.textualResolution.status === 'repaired') {
isolatedDiffSummary.textualConflicts += 1;
isolatedDiffSummary.resolverRepairs += 1;
} else {
isolatedDiffSummary.resolverFailures += 1;
}
}
if (integration.status === 'textual_conflict') {
isolatedDiffSummary.textualConflicts += 1;
await this.deps.runs.markFailed(runRow.id);

View file

@ -256,4 +256,49 @@ describe('parseIngestReportSnapshot', () => {
expect(() => parseIngestReportSnapshot(report)).toThrow('Invalid ingest report snapshot');
});
it('parses isolated-diff textual resolver counters', () => {
const snapshot = parseIngestReportSnapshot({
id: 'report-1',
runId: 'run-1',
jobId: 'job-1',
connectionId: 'warehouse',
sourceKey: 'metabase',
createdAt: '2026-05-18T00:00:00.000Z',
body: {
status: 'completed',
syncId: 'sync-1',
diffSummary: { added: 0, modified: 1, deleted: 0, unchanged: 0 },
commitSha: 'abc123',
isolatedDiff: {
enabled: true,
acceptedPatches: 2,
textualConflicts: 1,
semanticConflicts: 0,
resolverAttempts: 1,
resolverRepairs: 1,
resolverFailures: 0,
},
workUnits: [],
failedWorkUnits: [],
reconciliationSkipped: true,
conflictsResolved: [],
evictionsApplied: [],
unmappedFallbacks: [],
artifactResolutions: [],
evictionInputs: [],
unresolvedCards: [],
supersededBy: null,
overrideOf: null,
provenanceRows: [],
toolTranscripts: [],
},
});
expect(snapshot.body.isolatedDiff).toMatchObject({
resolverAttempts: 1,
resolverRepairs: 1,
resolverFailures: 0,
});
});
});

View file

@ -155,6 +155,9 @@ export const ingestReportSnapshotSchema = z
acceptedPatches: z.number().int().min(0),
textualConflicts: z.number().int().min(0),
semanticConflicts: z.number().int().min(0),
resolverAttempts: z.number().int().min(0).default(0),
resolverRepairs: z.number().int().min(0).default(0),
resolverFailures: z.number().int().min(0).default(0),
})
.optional(),
workUnits: z.array(

View file

@ -70,6 +70,9 @@ export interface IngestReportBody {
acceptedPatches: number;
textualConflicts: number;
semanticConflicts: number;
resolverAttempts?: number;
resolverRepairs?: number;
resolverFailures?: number;
};
workUnits: IngestReportWorkUnit[];
failedWorkUnits: string[];