fix(update): emit valid YAML flow arrays with quoted values#62
Open
ipreuss wants to merge 3 commits intowedow:masterfrom
Open
fix(update): emit valid YAML flow arrays with quoted values#62ipreuss wants to merge 3 commits intowedow:masterfrom
ipreuss wants to merge 3 commits intowedow:masterfrom
Conversation
Adds `tk update <id> --field=value` for modifying YAML frontmatter fields without opening an editor. Useful for AI agents and scripts. Features: - Update single or multiple fields in one command - JSON array syntax with jq: --tags='["a", "b"]' → tags: [a, b] - Graceful fallback when jq unavailable - Proper error handling for invalid arguments/JSON Also fixes update_yaml_field to work on macOS/BSD by using awk instead of GNU-specific sed syntax for inserting new fields. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Exit 0 on success (updated=$((updated+1)) instead of ((updated++))) - awk-based value replacement in both branches of update_yaml_field (eliminates sed metacharacter hazards: & / \) - Hybrid field policy via validate_field_update helper: - immutable: id, created - routed: status, deps, links - body-backed (rejected): title, description, design, acceptance - validated: priority (0-4), parent (must exist), type (known values) - freeform: everything else with [A-Za-z][A-Za-z0-9_-]* name - Reject array items with embedded commas (jq + no-jq paths) - Add 24 regression scenarios Ticket: M3R-7iue
Replace the comma-rejection guard (added during PR wedow#59 review) with structural quoting via jq @JSON. Values with commas, quotes, or backslashes now roundtrip losslessly as YAML 1.2 flow sequences (also valid JSON arrays) for non-iterated freeform fields. The 'tags' field stays comma-rejecting because tk ls -T, cmd_ready, cmd_blocked, and cmd_show iterate tag values via comma-split. The new error message names the readers explicitly. release_notes and other freeform array fields accept commas via storage roundtrip honored by tk query. Backward compatibility for existing .tickets/*.md: - Tags/deps/links readers strip quotes via widened gsub char class ([\[\] ] -> [\[\] "]); legacy unquoted and new quoted forms both parse to bare CSV for existing split() consumers. - ticket-query detects quoted form via /^\\[[[:space:]]*\"/ and emits verbatim (already valid JSON); legacy falls through to existing split-on-comma branch. cmd_update now requires jq for JSON-array values. Previously, jq absence triggered a regex-based fallback that accepted commas inconsistently. Fail-fast aligns with the rest of the codebase. update_yaml_field switched from awk -v to ENVIRON for the value, preserving JSON escape sequences (\", \\, \\n) byte-exact. Without this, awk -v's C-style escape processing would corrupt stored YAML when arrays contain quoted strings. 5 new behave scenarios: - Comma-in-value roundtrip (release_notes) - ticket-query on new quoted form - ticket-query on legacy unquoted form (regression guard) - ls -T on new quoted tags - ls -T on legacy unquoted tags (regression guard) Plus 3 scenarios codifying the tags-vs-freeform asymmetry: - tags array items rejected with comma (reader limitation) - comma-in-tag error names the reason - comma-in-value allowed for non-tag freeform fields Test framework: should-have-field-with-value and output-should-contain steps now support \" escapes in expected values, mirroring the existing 'I run' step. Two existing scenarios deleted (Reject array items with embedded commas, Comma-in-item error is specific) — their contract is replaced by the tags-specific case in validate_field_update. Full suite: 163/163 (was 157 baseline).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
updatecurrently rejects JSON arrays whose items contain commas (errorarray item contains comma). This was symptom-treatment added during PR #59 review findings 1-6. Legitimate user content — release notes, acceptance criteria in natural prose — commonly contains commas, and forcing users to rewrite content is friction with no structural upside.Fix
Replace
map(tostring)withmap(@json)incmd_update's jq pipeline so values roundtrip losslessly as valid YAML 1.2 flow sequences (also valid JSON arrays):Plus
echo→printf '%s\n'for byte-exact jq input.Tags-vs-freeform asymmetry (intentional)
tagsis the only freeform field that's reader-iterated (viatk ls -T,cmd_ready,cmd_blocked,cmd_show— theygsubbrackets/quotes/spaces andspliton comma). A comma-in-tag would phantom-match intk ls -T "foo"against a stored item"foo, bar". Sotagskeeps a comma-rejection guard viavalidate_field_update's newtagscase; the error names the readers explicitly.release_notesand other non-iterated freeform fields accept commas and roundtrip viatk query.Backward compatibility
Existing
.tickets/*.mdwith unquoted inline arrays keep working:[\[\] ]to[\[\] "]— strips quotes when present, no-op when absent.ticket-querydetects the quoted form via/^\[[[:space:]]*"/and emits verbatim (already valid JSON); legacy falls through to the existing split-on-comma branch.No migration required.
Other fixes in scope
update_yaml_fieldENVIRON switch:awk -vinterprets C-style escapes (\"→",\\→\), which would corrupt the JSON-escaped output fromjq @json. Switched toENVIRON["TK_FIELD_VALUE"]for byte-exact value passing. All 6 callers ofupdate_yaml_fieldbenefit.Tests
8 new behave scenarios (5 happy-path + 3 asymmetry):
release_notes)cmd_updaterejectstagswith comma (reader limitation, error names readers)release_notes)ticket-queryemits valid JSON for new quoted formticket-querystill handles legacy unquoted form (regression guard)tk ls -Tfilter on quoted tagstk ls -Tfilter on legacy unquoted tags (regression guard)Two existing scenarios deleted (general comma-rejection guard) — replaced by the tags-specific case in
validate_field_update. Existing tag-array scenario updated to expect quoted storage.Test framework also extended:
should have field with valueandoutput should containsteps now support\"escapes in expected values, mirroring the existingWhen I runstep.Full suite: 163/163 (was 157 baseline on
feature/update-command).Relationship to #59
This PR is stacked on
feature/update-command. When #59 merges, this one rebases onto master cleanly. Maintainer may alternatively choose to squash this into #59 directly.Plan B
If the
@jsonapproach is rejected, a downstream consumer (M3RPG, where the original release-note bug was reported) has a content-rewrite workaround already in hand as a data fix.