mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-13 01:14:56 +03:00
fix(db-load-xml): surface silent platform rejections + opt-in -StrictLog
Platform writes load-time property/type/enum rejections ("Неверное
свойство объекта метаданных", "Неизвестное имя типа" и т.п.) into the
/Out log but still exits with code 0, silently dropping the offending
metadata. db-load-xml now parses the log for these patterns and prints
a yellow "[warning] N rejection(s)" block to stdout so users (and the
model) can see them immediately.
Exit code still mirrors the platform by default — we don't second-guess
its verdict. With the new -StrictLog switch, rejection patterns are
elevated to exit code 1, which is the mode verify-snapshots.mjs uses
for honest E2E verdicts. All three db-load-xml call sites in the
verifier (main config, CFE base, CFE extension) now pass -StrictLog.
Found while investigating upload/form-baseline/gotchas.md #4 where AR
attribute emission was wrong but verify-snapshots showed green because
the old exit-code-only check missed the silent drops.
Bumped db-load-xml.ps1 + .py to v1.3.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# db-load-xml v1.1 — Load 1C configuration from XML files
|
# db-load-xml v1.3 — Load 1C configuration from XML files
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
@@ -98,7 +98,10 @@ param(
|
|||||||
[string]$Format = "Hierarchical",
|
[string]$Format = "Hierarchical",
|
||||||
|
|
||||||
[Parameter(Mandatory=$false)]
|
[Parameter(Mandatory=$false)]
|
||||||
[switch]$UpdateDB
|
[switch]$UpdateDB,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]$StrictLog
|
||||||
)
|
)
|
||||||
|
|
||||||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
@@ -213,20 +216,58 @@ try {
|
|||||||
$process = Start-Process -FilePath $V8Path -ArgumentList $arguments -NoNewWindow -Wait -PassThru
|
$process = Start-Process -FilePath $V8Path -ArgumentList $arguments -NoNewWindow -Wait -PassThru
|
||||||
$exitCode = $process.ExitCode
|
$exitCode = $process.ExitCode
|
||||||
|
|
||||||
|
# --- Read log ---
|
||||||
|
$logContent = $null
|
||||||
|
if (Test-Path $outFile) {
|
||||||
|
$logContent = Get-Content $outFile -Raw -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Scan log for silent rejections ---
|
||||||
|
# Platform often writes load-time rejections into /Out but exits with code 0.
|
||||||
|
# These patterns flag cases where metadata was dropped or rejected silently.
|
||||||
|
$fatalLogPatterns = @(
|
||||||
|
'Неверное свойство объекта метаданных',
|
||||||
|
'не входит в состав объекта метаданных',
|
||||||
|
'Неизвестное имя типа',
|
||||||
|
'Неизвестный объект метаданных',
|
||||||
|
'Ни один из документов не является регистратором для регистра',
|
||||||
|
'Неверное значение перечисления',
|
||||||
|
'не может быть приведен к типу'
|
||||||
|
)
|
||||||
|
$silentFailures = @()
|
||||||
|
if ($logContent) {
|
||||||
|
foreach ($line in ($logContent -split "`r?`n")) {
|
||||||
|
foreach ($pat in $fatalLogPatterns) {
|
||||||
|
if ($line -match [regex]::Escape($pat)) {
|
||||||
|
$silentFailures += $line.Trim()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# --- Result ---
|
# --- Result ---
|
||||||
|
# Default: mirror platform's verdict via exit code. Log content (including any
|
||||||
|
# rejection warnings) is always printed to stdout for visibility. With -StrictLog,
|
||||||
|
# elevate exit code to 1 when rejection patterns are found even if platform said 0.
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Load completed successfully" -ForegroundColor Green
|
Write-Host "Load completed successfully" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error loading configuration (code: $exitCode)" -ForegroundColor Red
|
Write-Host "Error loading configuration (code: $exitCode)" -ForegroundColor Red
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Test-Path $outFile) {
|
if ($logContent) {
|
||||||
$logContent = Get-Content $outFile -Raw -ErrorAction SilentlyContinue
|
Write-Host "--- Log ---"
|
||||||
if ($logContent) {
|
Write-Host $logContent
|
||||||
Write-Host "--- Log ---"
|
Write-Host "--- End ---"
|
||||||
Write-Host $logContent
|
}
|
||||||
Write-Host "--- End ---"
|
|
||||||
}
|
if ($silentFailures.Count -gt 0) {
|
||||||
|
$msg = "[warning] log contains $($silentFailures.Count) rejection(s) — platform loaded config but dropped properties/refs"
|
||||||
|
if (-not $StrictLog) { $msg += " (pass -StrictLog to treat as error)" }
|
||||||
|
Write-Host $msg -ForegroundColor Yellow
|
||||||
|
foreach ($f in $silentFailures) { Write-Host " $f" -ForegroundColor Yellow }
|
||||||
|
if ($StrictLog -and $exitCode -eq 0) { $exitCode = 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
exit $exitCode
|
exit $exitCode
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-load-xml v1.1 — Load 1C configuration from XML files
|
# db-load-xml v1.3 — Load 1C configuration from XML files
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -63,6 +63,11 @@ def main():
|
|||||||
help="File format (default: Hierarchical)",
|
help="File format (default: Hierarchical)",
|
||||||
)
|
)
|
||||||
parser.add_argument("-UpdateDB", action="store_true", help="Also update database configuration after load")
|
parser.add_argument("-UpdateDB", action="store_true", help="Also update database configuration after load")
|
||||||
|
parser.add_argument(
|
||||||
|
"-StrictLog",
|
||||||
|
action="store_true",
|
||||||
|
help="Treat silent rejection warnings in the log as errors (elevate exit code to 1)",
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# --- Resolve V8Path ---
|
# --- Resolve V8Path ---
|
||||||
@@ -157,22 +162,60 @@ def main():
|
|||||||
)
|
)
|
||||||
exit_code = result.returncode
|
exit_code = result.returncode
|
||||||
|
|
||||||
|
# --- Read log ---
|
||||||
|
log_content = ""
|
||||||
|
if os.path.isfile(out_file):
|
||||||
|
try:
|
||||||
|
with open(out_file, "r", encoding="utf-8-sig") as f:
|
||||||
|
log_content = f.read()
|
||||||
|
except Exception:
|
||||||
|
log_content = ""
|
||||||
|
|
||||||
|
# --- Scan log for silent rejections ---
|
||||||
|
# Platform often writes load-time rejections into /Out but exits with code 0.
|
||||||
|
# These patterns flag cases where metadata was dropped or rejected silently.
|
||||||
|
fatal_log_patterns = [
|
||||||
|
"Неверное свойство объекта метаданных",
|
||||||
|
"не входит в состав объекта метаданных",
|
||||||
|
"Неизвестное имя типа",
|
||||||
|
"Неизвестный объект метаданных",
|
||||||
|
"Ни один из документов не является регистратором для регистра",
|
||||||
|
"Неверное значение перечисления",
|
||||||
|
"не может быть приведен к типу",
|
||||||
|
]
|
||||||
|
silent_failures = []
|
||||||
|
if log_content:
|
||||||
|
for line in log_content.splitlines():
|
||||||
|
for pat in fatal_log_patterns:
|
||||||
|
if pat in line:
|
||||||
|
silent_failures.append(line.strip())
|
||||||
|
break
|
||||||
|
|
||||||
# --- Result ---
|
# --- Result ---
|
||||||
|
# Default: mirror platform's verdict via exit code. Log content (including any
|
||||||
|
# rejection warnings) is always printed to stdout for visibility. With -StrictLog,
|
||||||
|
# elevate exit code to 1 when rejection patterns are found even if platform said 0.
|
||||||
if exit_code == 0:
|
if exit_code == 0:
|
||||||
print("Load completed successfully")
|
print("Load completed successfully")
|
||||||
else:
|
else:
|
||||||
print(f"Error loading configuration (code: {exit_code})", file=sys.stderr)
|
print(f"Error loading configuration (code: {exit_code})", file=sys.stderr)
|
||||||
|
|
||||||
if os.path.isfile(out_file):
|
if log_content:
|
||||||
try:
|
print("--- Log ---")
|
||||||
with open(out_file, "r", encoding="utf-8-sig") as f:
|
print(log_content)
|
||||||
log_content = f.read()
|
print("--- End ---")
|
||||||
if log_content:
|
|
||||||
print("--- Log ---")
|
if silent_failures:
|
||||||
print(log_content)
|
suffix = "" if args.StrictLog else " (pass -StrictLog to treat as error)"
|
||||||
print("--- End ---")
|
print(
|
||||||
except Exception:
|
f"[warning] log contains {len(silent_failures)} rejection(s) — "
|
||||||
pass
|
f"platform loaded config but dropped properties/refs{suffix}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
for f in silent_failures:
|
||||||
|
print(f" {f}", file=sys.stderr)
|
||||||
|
if args.StrictLog and exit_code == 0:
|
||||||
|
exit_code = 1
|
||||||
|
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
|||||||
@@ -520,7 +520,7 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
execSkill(opts.runtime, 'db-load-xml/scripts/db-load-xml',
|
execSkill(opts.runtime, 'db-load-xml/scripts/db-load-xml',
|
||||||
['-V8Path', opts.v8ctx.v8path, '-InfoBasePath', dbDir, '-ConfigDir', baseConfigDir], 180_000);
|
['-V8Path', opts.v8ctx.v8path, '-InfoBasePath', dbDir, '-ConfigDir', baseConfigDir, '-StrictLog'], 180_000);
|
||||||
log('db-load-xml (config)', true);
|
log('db-load-xml (config)', true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const detail = (e.stderr || e.stdout || e.message).trim();
|
const detail = (e.stderr || e.stdout || e.message).trim();
|
||||||
@@ -551,7 +551,7 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) {
|
|||||||
if (existsSync(extDir)) {
|
if (existsSync(extDir)) {
|
||||||
try {
|
try {
|
||||||
execSkill(opts.runtime, 'db-load-xml/scripts/db-load-xml',
|
execSkill(opts.runtime, 'db-load-xml/scripts/db-load-xml',
|
||||||
['-V8Path', opts.v8ctx.v8path, '-InfoBasePath', dbDir, '-ConfigDir', extDir, '-Extension', extName], 180_000);
|
['-V8Path', opts.v8ctx.v8path, '-InfoBasePath', dbDir, '-ConfigDir', extDir, '-Extension', extName, '-StrictLog'], 180_000);
|
||||||
log('db-load-xml (ext)', true);
|
log('db-load-xml (ext)', true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const detail = (e.stderr || e.stdout || e.message).trim();
|
const detail = (e.stderr || e.stdout || e.message).trim();
|
||||||
@@ -624,7 +624,7 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
execSkill(opts.runtime, 'db-load-xml/scripts/db-load-xml',
|
execSkill(opts.runtime, 'db-load-xml/scripts/db-load-xml',
|
||||||
['-V8Path', opts.v8ctx.v8path, '-InfoBasePath', dbDir, '-ConfigDir', configDir], 180_000);
|
['-V8Path', opts.v8ctx.v8path, '-InfoBasePath', dbDir, '-ConfigDir', configDir, '-StrictLog'], 180_000);
|
||||||
log('db-load-xml', true);
|
log('db-load-xml', true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const detail = (e.stderr || e.stdout || e.message).trim();
|
const detail = (e.stderr || e.stdout || e.message).trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user