Skip to content

fix(workflows): keep non-ASCII text readable in run artifacts - #4877

Open
NishilRathod wants to merge 1 commit into
github:mainfrom
NishilRathod:fix/run-artifacts-non-ascii
Open

NishilRathod wants to merge 1 commit into
github:mainfrom
NishilRathod:fix/run-artifacts-non-ascii

Conversation

@NishilRathod

Copy link
Copy Markdown

Description

Fixes #4875.

Workflow run records under .specify/workflows/runs/<run_id>/ are meant to be human-auditable, but every writer used its serializer's ASCII-only default. Any non-English text in the run came out as \uXXXX escapes. This covers the definition snapshot (workflow.yml), state.json, inputs.json and log.jsonl.

This change writes the text as authored, using the same approach as #4148 (overlay YAML) and #4773 (merged JSON settings). All edits are in src/specify_cli/workflows/engine.py:

Artifact Writer Change
workflow.yml definition snapshot in WorkflowEngine.execute yaml.safe_dump(..., allow_unicode=True)
state.json, inputs.json RunState._atomic_write_json json.dump(..., ensure_ascii=False), temp file opened with errors="backslashreplace"
log.jsonl RunState.append_log json.dumps(..., ensure_ascii=False), file opened with errors="backslashreplace"

Why errors="backslashreplace": with ensure_ascii=False, a lone surrogate can't be encoded as UTF-8. One can arrive from an undecodable byte in a CLI argument via surrogateescape, and it would make save() raise. backslashreplace writes it as \udc80, which is itself a valid JSON escape, so it loads back as the same string. The YAML snapshot doesn't need this, because PyYAML already escapes non-printable characters, surrogates included, under allow_unicode=True. Nothing in src/ reads these files back except RunState.load, which already uses encoding="utf-8".

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable)

New tests in tests/test_workflows.py::TestRunState:

  • test_run_artifacts_keep_non_ascii_text_readable: CJK, Spanish and em-dash text in inputs, step results and a log entry must appear verbatim in state.json, inputs.json and log.jsonl, and round-trip through RunState.load.
  • test_workflow_snapshot_keeps_non_ascii_text_readable: engine.execute() on a workflow with a CJK name must write it verbatim in the run's workflow.yml.
  • test_run_artifacts_round_trip_a_lone_surrogate: an input containing "\udc80" must save and load back unchanged. This passes on main too; it guards the errors= choice.

The first two fail on main:

FAILED tests/test_workflows.py::TestRunState::test_run_artifacts_keep_non_ascii_text_readable
E   assert '演示:完整闭环 — ¿aprobar? 日本語' in '{\n  "run_id": "non-ascii-run", ... "演示:...'
FAILED tests/test_workflows.py::TestRunState::test_workflow_snapshot_keeps_non_ascii_text_readable
E   assert 'Demo Hello Pipeline (教学演示版)' in '... name: "Demo Hello Pipeline (\\u6559\\u5B66\\u6F14\\u793A\\u7248)" ...'

With this change:

$ uv run pytest tests/test_workflows.py -k "non_ascii or lone_surrogate"
3 passed
$ uvx ruff@0.15.0 check src tests
All checks passed!
$ uv run pytest
209 failed, 9650 passed, 231 skipped

The 209 failures all happen on this Windows machine with or without this change. Re-running the same 42 test files on unmodified main (1e933c4) fails exactly the same 209 tests, and none fails only on this branch. They're mostly the bash-vs-Python script parity tests and symlink tests (creating symlinks on Windows needs Developer Mode or admin rights). Nothing in the workflow run/state tests changed.

Sample project, using the real CLI on Windows 11 (10.0.26200) with Python 3.12. The workflow has name: "Demo Hello Pipeline (教学演示版)" and a shell step, run as specify workflow run demo.yml -i spec="演示:完整闭环":

before  workflow.yml ->   name: "Demo Hello Pipeline (教学演示版)"
before  inputs.json  ->     "spec": "演示:完整闭环"
after   workflow.yml ->   name: Demo Hello Pipeline (教学演示版)
after   inputs.json  ->     "spec": "演示:完整闭环"

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: Implemented with Claude Code (desktop app) using Claude Opus 5.5 at xhigh reasoning effort, in autonomous agent mode under my direction. I chose the issue and approved the plan; the agent wrote the code change, the tests and this PR description, and ran all of the testing above on my Windows machine. Commits carry an Assisted-by: trailer.

The run records under .specify/workflows/runs/<run_id>/ are meant to be
human-auditable, but every writer used the serializer's ASCII-only
default, so non-English text in the definition snapshot (workflow.yml),
state.json, inputs.json and log.jsonl came out as \uXXXX escapes.

Write them as authored: allow_unicode=True for the YAML snapshot and
ensure_ascii=False for the JSON/JSONL writers, as github#4148 and github#4773 did for
overlay files and merged settings. The JSON writers also use
errors="backslashreplace", so a lone surrogate (an undecodable byte in a
CLI argument) is still written as its JSON \u escape and loads back
unchanged instead of failing the save.

Fixes github#4875

Assisted-by: Claude Code (model: Claude Opus 5.5, autonomous)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused serialization changes are consistent with existing patterns and have appropriate regression coverage.

0 open findings

What changed in this PR

Makes workflow run artifacts human-readable for non-ASCII content while safely preserving lone surrogates.

Changes:

  • Enables Unicode output for YAML and JSON artifacts.
  • Adds non-ASCII readability and surrogate round-trip regression tests.
  • Baseline results rely on the provided fail-before/pass-after evidence.
File Description
src/​specify_cli/​workflows/​engine.py Writes readable Unicode with safe surrogate fallback.
tests/​test_workflows.py Covers all affected artifacts and edge cases.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Workflow run artifacts (snapshot/state/inputs/logs) escape non-ASCII text as \uXXXX

2 participants