diff --git a/.claude/skills/mxl-compile/reference/dsl-spec.md b/.claude/skills/mxl-compile/reference/dsl-spec.md
index 45a5161d..90a2f6f6 100644
--- a/.claude/skills/mxl-compile/reference/dsl-spec.md
+++ b/.claude/skills/mxl-compile/reference/dsl-spec.md
@@ -179,7 +179,7 @@
| `rowspan` | нет | `1` | Объединение по вертикали (количество строк) |
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
| `param` | нет | — | Параметр заполнения |
-| `detail` | нет | — | Параметр расшифровки (только с `param`) |
+| `detail` | нет | — | Параметр расшифровки. Самостоятельный ключ: ставится и на ячейку без `param` — с текстом, пустую или поле ввода |
| `text` | нет | — | Статический текст. Строка или объект `{ ru, en }` — см. ниже |
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
| `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) |
diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1
index 16a3d0fc..159b1b2e 100644
--- a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1
+++ b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1
@@ -1711,9 +1711,6 @@ foreach ($area in $def.areas) {
if ($cellInfo.Param) {
X "`t`t`t`t`t$($cellInfo.Param)"
- if ($cellInfo.Detail) {
- X "`t`t`t`t`t$($cellInfo.Detail)"
- }
}
# Проверяем НАЛИЧИЕ ключа, а не истинность: пустая строка — это текст, платформа
@@ -1722,6 +1719,14 @@ foreach ($area in $def.areas) {
if ($null -ne $cellInfo.Template) { Emit-CellText $cellInfo.Template }
+ # Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут
+ # её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
+ # Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
+ # Порядок тегов ячейки снят с корпуса: parameter · текст · detailParameter.
+ if ($cellInfo.Detail) {
+ X "`t`t`t`t`t$($cellInfo.Detail)"
+ }
+
X "`t`t`t`t"
X "`t`t`t"
}
diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.py b/.claude/skills/mxl-compile/scripts/mxl-compile.py
index 449522ee..385ed8fb 100644
--- a/.claude/skills/mxl-compile/scripts/mxl-compile.py
+++ b/.claude/skills/mxl-compile/scripts/mxl-compile.py
@@ -1658,8 +1658,6 @@ def main():
if cell_info['Param']:
lines.append(f'\t\t\t\t\t{cell_info["Param"]}')
- if cell_info['Detail']:
- lines.append(f'\t\t\t\t\t{cell_info["Detail"]}')
# Проверяем НАЛИЧИЕ ключа, а не истинность: пустая строка — это текст,
# платформа такие ячейки пишет с пустым , и по истинности он терялся.
@@ -1669,6 +1667,13 @@ def main():
if cell_info['Template'] is not None:
emit_cell_text(lines, cell_info['Template'])
+ # Расшифровка от параметра заполнения не зависит: на корпусе 20 404 ячейки несут
+ # её БЕЗ параметра (у текста, у пустой ячейки, у поля ввода) против 8 582 с ним.
+ # Пока она стояла внутри ветки параметра, две трети расшифровок терялись молча.
+ # Порядок тегов ячейки снят с корпуса: parameter · текст · detailParameter.
+ if cell_info['Detail']:
+ lines.append(f'\t\t\t\t\t{cell_info["Detail"]}')
+
lines.append('\t\t\t\t')
lines.append('\t\t\t')
diff --git a/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1 b/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1
index 33f6a5f1..137eb483 100644
--- a/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1
+++ b/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1
@@ -1035,7 +1035,9 @@ foreach ($area in $blocks) {
# значение задаёт её формат. Без этого такая строка уходила бы в пустые.
$cf = Get-Format $cell.FormatIdx
$hasValue = ($cf -and $cf.Props['containsValue'] -ceq 'true')
- $hasContent = $cell.Param -or $cell.HasText -or $hasValue
+ # Расшифровка сама по себе делает ячейку содержательной: в корпусе 12 653 ячейки
+ # несут только её. Без этого такая ячейка уходила в заполнители и терялась.
+ $hasContent = $cell.Param -or $cell.HasText -or $hasValue -or $cell.Detail
$hasMerge = $mergeMap.ContainsKey("$globalRow,$($cell.Col)")
if ($hasContent -or $hasMerge) {
@@ -1140,12 +1142,15 @@ foreach ($area in $blocks) {
if ($cell.Param) {
$dslCell["param"] = $cell.Param
- if ($cell.Detail) { $dslCell["detail"] = $cell.Detail }
} elseif ($fillType -eq "Template" -and $cell.HasText) {
$dslCell["template"] = Get-DslText $cell.Text
} elseif ($cell.HasText) {
$dslCell["text"] = Get-DslText $cell.Text
}
+ # Расшифровка живёт отдельно от параметра заполнения: на корпусе 20 404 ячейки
+ # несут её без параметра против 8 582 с ним. Пока она читалась только вместе
+ # с параметром, две трети расшифровок терялись молча.
+ if ($cell.Detail) { $dslCell["detail"] = $cell.Detail }
$dslCells += $dslCell
}
diff --git a/.claude/skills/mxl-decompile/scripts/mxl-decompile.py b/.claude/skills/mxl-decompile/scripts/mxl-decompile.py
index e59dc9d4..9e330249 100644
--- a/.claude/skills/mxl-decompile/scripts/mxl-decompile.py
+++ b/.claude/skills/mxl-decompile/scripts/mxl-decompile.py
@@ -1032,7 +1032,9 @@ def main():
# нет: значение задаёт её формат. Без этого такая строка уходила бы в пустые.
cf = get_format(cell["FormatIdx"])
has_value = bool(cf and cf["Props"].get("containsValue") == "true")
- has_content = cell["Param"] or cell["HasText"] or has_value
+ # Расшифровка сама по себе делает ячейку содержательной: в корпусе 12 653 ячейки
+ # несут только её. Без этого такая ячейка уходила в заполнители и терялась.
+ has_content = cell["Param"] or cell["HasText"] or has_value or cell["Detail"]
has_merge = f"{global_row},{cell['Col']}" in merge_map
if has_content or has_merge:
@@ -1132,12 +1134,15 @@ def main():
if cell["Param"]:
dsl_cell["param"] = cell["Param"]
- if cell["Detail"]:
- dsl_cell["detail"] = cell["Detail"]
elif fill_type == "Template" and cell["HasText"]:
dsl_cell["template"] = get_dsl_text(cell["Text"])
elif cell["HasText"]:
dsl_cell["text"] = get_dsl_text(cell["Text"])
+ # Расшифровка живёт отдельно от параметра заполнения: на корпусе 20 404 ячейки
+ # несут её без параметра против 8 582 с ним. Пока она читалась только вместе
+ # с параметром, две трети расшифровок терялись молча.
+ if cell["Detail"]:
+ dsl_cell["detail"] = cell["Detail"]
dsl_cells.append(dsl_cell)
diff --git a/docs/mxl-dsl-spec.md b/docs/mxl-dsl-spec.md
index c0bceafb..21b44a8e 100644
--- a/docs/mxl-dsl-spec.md
+++ b/docs/mxl-dsl-spec.md
@@ -179,7 +179,7 @@
| `rowspan` | нет | `1` | Объединение по вертикали (количество строк) |
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
| `param` | нет | — | Параметр заполнения |
-| `detail` | нет | — | Параметр расшифровки (только с `param`) |
+| `detail` | нет | — | Параметр расшифровки. Самостоятельный ключ: ставится и на ячейку без `param` — с текстом, пустую или поле ввода |
| `text` | нет | — | Статический текст. Строка или объект `{ ru, en }` — см. ниже |
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
| `valueType` | нет | — | Тип значения: ячейка становится полем ввода (см. ниже) |
diff --git a/tests/skills/cases/mxl-compile/detail-without-param.json b/tests/skills/cases/mxl-compile/detail-without-param.json
new file mode 100644
index 00000000..af433e96
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/detail-without-param.json
@@ -0,0 +1,21 @@
+{
+ "name": "Расшифровка без параметра заполнения",
+ "input": {
+ "columns": 3,
+ "areas": [
+ {
+ "name": "Расшифровки",
+ "rows": [
+ { "cells": [
+ { "col": 1, "text": "Итого", "detail": "ПоказательИтога" },
+ { "col": 2, "detail": "ПустаяЯчейка" },
+ { "col": 3, "param": "Сумма", "detail": "Расшифровка" }
+ ]}
+ ]
+ }
+ ]
+ },
+ "params": {
+ "outputPath": "Template.xml"
+ }
+}
diff --git a/tests/skills/cases/mxl-compile/snapshots/detail-without-param/Template.xml b/tests/skills/cases/mxl-compile/snapshots/detail-without-param/Template.xml
new file mode 100644
index 00000000..466d76df
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/snapshots/detail-without-param/Template.xml
@@ -0,0 +1,65 @@
+
+
+
+ ru
+ ru
+
+ ru
+ Русский
+ Русский
+
+
+
+ 3
+
+
+ 0
+
+
+
+ 0
+
+
+ ru
+ Итого
+
+
+ ПоказательИтога
+
+
+
+
+ 0
+ ПустаяЯчейка
+
+
+
+
+ 1
+ Сумма
+ Расшифровка
+
+
+
+
+ true
+ 2
+ 1
+ 1
+
+ Расшифровки
+
+ Rows
+ 0
+ 0
+ -1
+ -1
+
+
+
+ Parameter
+
+
+ 10
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-decompile/roundtrip-detail-without-param.json b/tests/skills/cases/mxl-decompile/roundtrip-detail-without-param.json
new file mode 100644
index 00000000..47b7a9f5
--- /dev/null
+++ b/tests/skills/cases/mxl-decompile/roundtrip-detail-without-param.json
@@ -0,0 +1,31 @@
+{
+ "name": "Roundtrip — расшифровка без параметра заполнения",
+ "preRun": [
+ {
+ "script": "mxl-compile/scripts/mxl-compile",
+ "input": {
+ "columns": 3,
+ "areas": [
+ {
+ "name": "Расшифровки",
+ "rows": [
+ { "cells": [
+ { "col": 1, "text": "Итого", "detail": "ПоказательИтога" },
+ { "col": 2, "detail": "ПустаяЯчейка" },
+ { "col": 3, "param": "Сумма", "detail": "Расшифровка" }
+ ]}
+ ]
+ }
+ ]
+ },
+ "args": { "-JsonPath": "{inputFile}", "-OutputPath": "Template.xml" },
+ "cwd": "{workDir}"
+ }
+ ],
+ "params": { "templatePath": "Template.xml" },
+ "args_extra": ["-OutputPath", "{workDir}/back.json"],
+ "expect": {
+ "files": ["back.json"],
+ "stdoutContains": "[OK] Decompiled:"
+ }
+}
diff --git a/tests/skills/cases/mxl-decompile/snapshots/roundtrip-detail-without-param/Template.xml b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-detail-without-param/Template.xml
new file mode 100644
index 00000000..466d76df
--- /dev/null
+++ b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-detail-without-param/Template.xml
@@ -0,0 +1,65 @@
+
+
+
+ ru
+ ru
+
+ ru
+ Русский
+ Русский
+
+
+
+ 3
+
+
+ 0
+
+
+
+ 0
+
+
+ ru
+ Итого
+
+
+ ПоказательИтога
+
+
+
+
+ 0
+ ПустаяЯчейка
+
+
+
+
+ 1
+ Сумма
+ Расшифровка
+
+
+
+
+ true
+ 2
+ 1
+ 1
+
+ Расшифровки
+
+ Rows
+ 0
+ 0
+ -1
+ -1
+
+
+
+ Parameter
+
+
+ 10
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/mxl-decompile/snapshots/roundtrip-detail-without-param/back.json b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-detail-without-param/back.json
new file mode 100644
index 00000000..b491a6b3
--- /dev/null
+++ b/tests/skills/cases/mxl-decompile/snapshots/roundtrip-detail-without-param/back.json
@@ -0,0 +1 @@
+{ "columns": 3, "defaultWidth": 10, "fonts": {}, "styles": {}, "areas": [{ "name": "Расшифровки", "rows": [[{ "text": "Итого", "detail": "ПоказательИтога" }, { "detail": "ПустаяЯчейка" }, { "param": "Сумма", "detail": "Расшифровка" }]] }] }
\ No newline at end of file