fix: resolve evaluation serialization, benchmark metrics, encoding, and script stability issues - #1602
Conversation
Babysit review — please split and rebaseThis PR mixes 5 unrelated change types (utf-8 batch fix, MCP serialization, soffice platform shim, viewer.html XSS escaping, custom YAML fallback parser) across 18 files AND is currently
|
7e3bbd0 to
ae37d8a
Compare
|
Rebased cleanly on latest
|
98zc5g5jyw-arch
left a comment
There was a problem hiding this comment.
Review: fix: resolve evaluation serialization, benchmark metrics, encoding, and script stability issues
Verdict: Approve with minor comments (COMMENT)
No critical issues found. The serialization, metric-direction, encoding, and stability fixes are genuine and verified against the actual data shapes in the repo (e.g. connections.call_tool returns result.content, a list of content blocks, so the new _serialize_tool_result list branch actually triggers). A few robustness nits and one bounded busy-spin edge case below.
Verified correct (looks good)
mcp-builder/scripts/evaluation.py:86-100—_serialize_tool_resultcorrectly unwrapsTextContent.textfor the reallist[ContentBlock]shape returned byconnections.py:70(result.content). Confirmed with a mock of the SDK types.skill-creator/scripts/aggregate_benchmark.py:211-218— delta direction fix is order-independent and correct; checked all 8 orderings ofwith_skill/without_skill/new_skill/old_skill, including the alphabetical-sort case that caused the original sign inversion.eval_namepreservation (lines 132, 249) is clean.skill-creator/eval-viewer/generate_review.py:280—.replace("</", "<\\/")is safe:json.dumpsnever emits a bare\/(backslashes are doubled), so no double-escaping;\/round-trips throughJSON.parseto/; the</scriptsequence is gone from the inline script. Verified by round-trip test.skill-creator/eval-viewer/viewer.html:1097-1102, 1133-1137, 1229-1242—escapeHtmlnow encodes"and'; all interpolated fields are wrapped. Correct.skill-creator/scripts/run_eval.py:102-114, 132-152— removing the unconditionalbreakafter the post-exit drain (which skipped line processing) and replacing earlyreturn Falsewithcontinue/pending_tool_name = Nonefixes real false negatives. The deadselectpath is now live.docx/scripts/accept_changes.py:78-82— timeout now returns an error message instead of a fake success (CLI already gates on"Error" in message, so this is a genuine fix).pdf/scripts/extract_form_field_info.py:48(get_fields() or {}),pdf/scripts/convert_pdf_to_images.py:10(os.makedirs(..., exist_ok=True)),quick_validate.py(UTF-8 read + empty name/description now rejected),utils.pycontinuation handling (blank lines inside folded descriptions), soffice_needs_shimplatform gate (soffice.py:55-63),with_server.pyprocess-group kill,init-artifact.shsed/existsSync guards — all correct.- No new imports beyond stdlib; no dependency-declaration violations.
Warnings
skill-creator/scripts/run_eval.py:101-114, 170-171— busy-spin on truncated final line. If the process exits with a partial line inbuffer(no trailing\n),process.stdout.read()keeps returningb"", the line-processing loop never fires, andpoll() is not None and not bufferis False, so the loop spins (CPU burn) until the outertime.time() - start_time < timeoutexpires. Bounded by timeout, results unaffected, but a worker burns a full core for up totimeoutseconds. Suggest tracking EOF (e.g. break whenprocess.poll() is not None and not remainingor when read returnsb""), not just when the buffer is empty.- Incomplete UTF-8 enforcement in
aggregate_benchmark.py— the PR's stated goal ("Enforced UTF-8 encoding") is only partially applied:open(timing_file)(line 146) and both output writesopen(output_json, "w")/open(output_md, "w")(lines 387/393) still use locale-default encoding. On Windows (cp1252 default), a non-ASCII skill name or eval name will raiseUnicodeEncodeErrorwhen writingbenchmark.json/.md. Same forpdf/scripts/extract_form_field_info.py:113(open(json_output_path, "w")). This diverges from theencoding="utf-8"standard already applied in quick_validate.py/utils.py here and in #1591/#1596. webapp-testing/scripts/with_server.py:70-77— DEVNULL discards server logs entirely; a server that starts, binds the port, then crashes at request time is now undiagnosable, and"Server N stopped"(line 113) prints even when the kill was swallowed. Acceptable trade-off for the deadlock fix, but consider redirecting to a per-server temp log file (or at least documenting the loss).docx/scripts/accept_changes.py:18, 63—file://{LIBREOFFICE_PROFILE}uses a raw temp path.tempfile.gettempdir()on Windows (e.g.C:\Users\First Last\AppData\Local\Temp) contains spaces and backslashes that break the unencodedfile://URI; also a fixed shared profile dir is unsafe for concurrent runs (pre-existing). PreferPath(...).as_uri()for the-env:UserInstallationvalue.
Suggestions
mcp-builder/scripts/evaluation.py:86-100— guardblock.textbeingNone(parts.append(block.text or "")): aNonetext member currently raisesTypeErrorinside the join, which the caller'stry/exceptdegrades into an "Error executing tool" message. Also consider defensively unwrappingresult.contentwhen a non-listCallToolResult-like object is passed (older SDK shapes fall back tostr()repr today).soffice.py:50/accept_changes.py:14— move the newly addedimport platform/import tempfileto the top import block (PEP8); mid-file placement after other imports is legal but easy to miss in review.skill-creator/scripts/package_skill.py:116-119—main()'s usage text still sayspython utils/package_skill.pywhile the docstring now sayspython -m scripts.package_skill; align them.skills/claude-api/SKILL.md:2-3— the description/trigger text was substantially trimmed (SKIP clause dropped the "overrides all triggers" phrasing). This changes trigger behavior for every consumer of the skill; please confirm the reduced wording was intentional (token savings) and still covers the intended skip cases.
… and import styling
|
Thanks for the thorough and constructive review @98zc5g5jyw-arch! I've addressed all the feedback in commit
All 19 skills passed validation via |
98zc5g5jyw-arch
left a comment
There was a problem hiding this comment.
Re-review after 851a1a9: review feedback addressed — soffice UserInstallation now uses Path.as_uri(), tool_result.content handled via hasattr/getattr, empty text blocks guarded with 'or ""', UTF-8 encoding added to JSON writes, import ordering fixed. All changes correct. LGTM.
Summary of Changes
This PR resolves multiple reliability, platform compatibility, and metric calculation bugs across the skills repository:
mcp-builder ():
skill-creator ():
old_skillto be treated as primary andwith_skillas baseline.eval_namefromeval_metadata.jsoninbenchmark.jsonruns.skill-creator eval viewer ( & ):
escapeHtml()to encode double and single quotes (",'), preventing layout breakage and attribute injection in tooltips.</script>tag sequences in embedded JSON.skill-creator validation & utils (, , ):
quick_validate.pyso validation works even if PyYAML is not installed.nameanddescription.utils.pyacross blank lines.package_skill.pyand corrected CLI help documentation.webapp-testing ():
DEVNULLfor piped subprocess streams to prevent buffer deadlocks on long builds.pdf & docx & office tools:
extract_form_field_info.pyto avoidAttributeError.convert_pdf_to_images.py.accept_changes.py.soffice.py.web-artifacts-builder ():
<link rel="icon"tags for modern Vite scaffolds.tsconfig.app.jsonupdates when the file is absent.Skills Frontmatter Compliance:
claude-apiandclaude-academy-guidedescriptions to comply with the 1024-character specification limit.Testing & Verification
quick_validate.py(100% pass rate).