From c2cac9bfe2fad384e8a5e6b80fd2ffb6971fd789 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 20 Oct 2026 19:50:03 +0000 Subject: [PATCH] refactor(observation): share web runtime partial retention Observe and inspect used the same promote-or-keep path. One helper owns that sequence so the two operations cannot drift. Co-authored-by: morluto --- src/application/WebRuntimeService.ts | 105 ++++++++++++--------------- 1 file changed, 47 insertions(+), 58 deletions(-) diff --git a/src/application/WebRuntimeService.ts b/src/application/WebRuntimeService.ts index f6922fb973..627ada4906 100644 --- a/src/application/WebRuntimeService.ts +++ b/src/application/WebRuntimeService.ts @@ -41,36 +41,19 @@ export class WebRuntimeService { ); if (!parsed.ok) return parsed; const result = await this.provider.observeExecution(parsed.value, options); - if (!result.ok) { - const partial = result.error.partialObservation; - if ( - partial !== undefined && - !("evidence_id" in partial) && - "instrumentation" in partial && - "window" in partial - ) { - const verifiedPartial = webExecutionSchema.safeParse(partial); - if (verifiedPartial.success) { - const evidence = this.evidence( - operation, - parsed.value, - verifiedPartial.data, - ); - if (evidence.ok) { - result.error.partialObservation = evidence.value; - return result; - } - if (result.error instanceof AnalysisCancelledError) return evidence; - } - } - return err( - keepIncompleteObservation( - result.error, - operation, - "Provider retained a non-JSON incomplete execution observation.", - ), + if (!result.ok) + return this.retainRuntimePartial( + result.error, + operation, + "Provider retained a non-JSON incomplete execution observation.", + (partial) => { + if (!("instrumentation" in partial) || !("window" in partial)) + return undefined; + const verified = webExecutionSchema.safeParse(partial); + if (!verified.success) return undefined; + return this.evidence(operation, parsed.value, verified.data); + }, ); - } const verified = webExecutionSchema.safeParse(result.value); if (!verified.success) return err(new AnalysisOutputError(operation, verified.error.message)); @@ -104,36 +87,19 @@ export class WebRuntimeService { parsed.value, options, ); - if (!result.ok) { - const partial = result.error.partialObservation; - if ( - partial !== undefined && - !("evidence_id" in partial) && - "selected_node" in partial && - "listeners" in partial - ) { - const verifiedPartial = webEventListenersSchema.safeParse(partial); - if (verifiedPartial.success) { - const evidence = this.evidence( - operation, - parsed.value, - verifiedPartial.data, - ); - if (evidence.ok) { - result.error.partialObservation = evidence.value; - return result; - } - if (result.error instanceof AnalysisCancelledError) return evidence; - } - } - return err( - keepIncompleteObservation( - result.error, - operation, - "Provider retained a non-JSON incomplete event-listener observation.", - ), + if (!result.ok) + return this.retainRuntimePartial( + result.error, + operation, + "Provider retained a non-JSON incomplete event-listener observation.", + (partial) => { + if (!("selected_node" in partial) || !("listeners" in partial)) + return undefined; + const verified = webEventListenersSchema.safeParse(partial); + if (!verified.success) return undefined; + return this.evidence(operation, parsed.value, verified.data); + }, ); - } const verified = webEventListenersSchema.safeParse(result.value); if (!verified.success) return err(new AnalysisOutputError(operation, verified.error.message)); @@ -150,6 +116,29 @@ export class WebRuntimeService { return this.evidence(operation, parsed.value, verified.data, options); } + /** Promote a schema-valid partial, or keep a JSON snapshot of an incomplete one. */ + private retainRuntimePartial( + error: AnalysisError, + operation: string, + nonJsonReason: string, + promote: ( + partial: NonNullable, + ) => Result | undefined, + ): Result { + const partial = error.partialObservation; + if (partial !== undefined && !("evidence_id" in partial)) { + const evidence = promote(partial); + if (evidence !== undefined) { + if (evidence.ok) { + error.partialObservation = evidence.value; + return err(error); + } + if (error instanceof AnalysisCancelledError) return evidence; + } + } + return err(keepIncompleteObservation(error, operation, nonJsonReason)); + } + private evidence( operation: string, input: