From 99dcd7c0453269f81e513234a916c04a7b2640b0 Mon Sep 17 00:00:00 2001 From: Wu Sheng Date: Fri, 3 Jul 2026 12:20:59 +0800 Subject: [PATCH 1/2] live-debug: show the LAL drop reason MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OAP dsl-debugging session response now carries an optional per-sample 'reason' explaining WHY a LAL step stopped the pipeline (parse failure, non-matching regexp, non-log-body input). Surface it in the live debugger: - api-client: add optional SessionSample.reason. - LalCell: render the reason under the abort marker when present. - DebugLal: pass the sample's reason to the cell. - i18n: add the 'drop reason' label (en + zh-CN). Backward compatible: reason is optional, so an OAP version that does not send it (older dev builds) renders exactly as before — the block only appears when a reason is present. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- .../features/operate/live-debug/DebugLal.vue | 1 + .../features/operate/live-debug/LalCell.vue | 32 +++++++++++++++++++ apps/ui/src/i18n/locales/en.json | 1 + apps/ui/src/i18n/locales/zh-CN.json | 1 + packages/api-client/src/dsl-debugging.ts | 8 ++++- 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/apps/ui/src/features/operate/live-debug/DebugLal.vue b/apps/ui/src/features/operate/live-debug/DebugLal.vue index 29c7f3f0..7398832b 100644 --- a/apps/ui/src/features/operate/live-debug/DebugLal.vue +++ b/apps/ui/src/features/operate/live-debug/DebugLal.vue @@ -970,6 +970,7 @@ function recordTitle(view: LalRecordView): string { diff --git a/apps/ui/src/features/operate/live-debug/LalCell.vue b/apps/ui/src/features/operate/live-debug/LalCell.vue index b85408f9..5a96635e 100644 --- a/apps/ui/src/features/operate/live-debug/LalCell.vue +++ b/apps/ui/src/features/operate/live-debug/LalCell.vue @@ -40,6 +40,9 @@ import { const props = defineProps<{ stepType: SampleType; payload: LalSamplePayload | null; + /** Why this step stopped the pipeline (parse failure, non-matching regexp, …), + * or null/undefined when it continued or the OAP version doesn't report it. */ + reason?: string | null; /** When set (the cell popout), body/content shows its complete pretty- * printed value instead of the 80-char dense-matrix preview. */ full?: boolean; @@ -119,6 +122,10 @@ const outputKvs = computed(() => outputEntries(props.payload, props.full));
{{ t('aborted') }}
+
+ {{ t('drop reason') }} + {{ props.reason }} +
diff --git a/apps/ui/src/i18n/locales/en.json b/apps/ui/src/i18n/locales/en.json index 667ab15e..b3e44fa2 100644 --- a/apps/ui/src/i18n/locales/en.json +++ b/apps/ui/src/i18n/locales/en.json @@ -335,6 +335,7 @@ "carried": "carried", "+ added": "+ added", "aborted": "aborted", + "drop reason": "drop reason", "file": "file", "select an .oal file…": "select an .oal file…", "metric": "metric", diff --git a/apps/ui/src/i18n/locales/zh-CN.json b/apps/ui/src/i18n/locales/zh-CN.json index a6e736cc..716866a1 100644 --- a/apps/ui/src/i18n/locales/zh-CN.json +++ b/apps/ui/src/i18n/locales/zh-CN.json @@ -331,6 +331,7 @@ "carried": "继承", "+ added": "+ 新增", "aborted": "已中止", + "drop reason": "丢弃原因", "file": "文件", "select an .oal file…": "选择一个 .oal 文件…", "metric": "指标", diff --git a/packages/api-client/src/dsl-debugging.ts b/packages/api-client/src/dsl-debugging.ts index f40404a9..0489786e 100644 --- a/packages/api-client/src/dsl-debugging.ts +++ b/packages/api-client/src/dsl-debugging.ts @@ -432,13 +432,19 @@ export type SamplePayload = * - `payload`: per-DSL shape — see the per-DSL types above. * - `sourceLine`: 1-based line number in the rule body. Omitted when * 0 / not applicable (block-level LAL probes, MAL chain stages on - * a one-liner rule). */ + * a one-liner rule). + * - `reason`: human-readable explanation of WHY this step stopped the + * pipeline (a parse exception, a non-matching regexp, an input-type + * mismatch), paired with `continueOn: false`. Optional — LAL-only + * today, and absent from OAP versions before it was added, so the + * UI must treat its absence as "no reason available". */ export interface SessionSample { type: SampleType; sourceText: string; continueOn: boolean; payload: SamplePayload; sourceLine?: number; + reason?: string; } /** Catalog-specific structured rule metadata. The recorder fills in From 7609abae85f0dde72acffd38b08a2e7e9faffbdc Mon Sep 17 00:00:00 2001 From: Wu Sheng Date: Fri, 3 Jul 2026 14:20:51 +0800 Subject: [PATCH 2/2] live-debug: also show the LAL drop reason in the cell detail popout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reason rendered in the dense matrix cell — where it truncates like any long value — but not in the full-cell popout, which is where you go to read a cell in full. Add a `reason` prop + wrapped block to LalCellPopout and thread the sample's reason through openCellPopout so the detail view shows the complete explanation. --- .../features/operate/live-debug/DebugLal.vue | 3 ++ .../operate/live-debug/LalCellPopout.vue | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/apps/ui/src/features/operate/live-debug/DebugLal.vue b/apps/ui/src/features/operate/live-debug/DebugLal.vue index 7398832b..16b3c078 100644 --- a/apps/ui/src/features/operate/live-debug/DebugLal.vue +++ b/apps/ui/src/features/operate/live-debug/DebugLal.vue @@ -428,6 +428,7 @@ const popoutComparable = ref< >([]); const popoutDslLines = ref([]); const popoutCurrentLine = ref(0); +const popoutReason = ref(null); /** Brace-match a top-level DSL block (`extractor {` … `}`) and return its * 1-based line span, or null when the opener isn't present. */ @@ -467,6 +468,7 @@ function openCellPopout(cell: LalCellData, step: LalStep, node: LalNodeView): vo popoutJson.value = fullJson(cell.payload, step.type); popoutDslLines.value = sourceDslLines.value; popoutCurrentLine.value = stepLines(step).start; + popoutReason.value = cell.sample.reason ?? null; // Comparable = the record's other same-format (builder) cells. Per- // statement snapshots map to their DSL line; the post-extractor / // output snapshots map to their whole block range, so the captured @@ -986,6 +988,7 @@ function recordTitle(view: LalRecordView): string { :title="popoutTitle" :script="popoutScript" :json="popoutJson" + :reason="popoutReason" :comparable="popoutComparable" :dsl-lines="popoutDslLines" :current-line="popoutCurrentLine" diff --git a/apps/ui/src/features/operate/live-debug/LalCellPopout.vue b/apps/ui/src/features/operate/live-debug/LalCellPopout.vue index 2fe7fcda..cfc092de 100644 --- a/apps/ui/src/features/operate/live-debug/LalCellPopout.vue +++ b/apps/ui/src/features/operate/live-debug/LalCellPopout.vue @@ -40,6 +40,8 @@ const props = defineProps<{ script: string; /** The opened cell's complete payload, pretty JSON. */ json: string; + /** Why this step stopped the pipeline, or null when it continued. */ + reason?: string | null; /** Same-format sibling cells. `lineStart..lineEnd` is the DSL span * (equal for per-statement steps, the block range for block steps). */ comparable: { label: string; script: string; json: string; lineStart: number; lineEnd: number }[]; @@ -114,6 +116,11 @@ function clearCompare(): void {
{{ script }}
+
+ {{ t('drop reason') }} + {{ reason }} +
+
{{ t('compare with') }}