Skip to content

fix(claude): make argument-hint injection fold-aware for long descriptions - #4045

Open
chelsealong wants to merge 2 commits into
github:mainfrom
chelsealong:fix/claude-argument-hint-folded-description
Open

fix(claude): make argument-hint injection fold-aware for long descriptions#4045
chelsealong wants to merge 2 commits into
github:mainfrom
chelsealong:fix/claude-argument-hint-folded-description

Conversation

@chelsealong

Copy link
Copy Markdown
Contributor

Summary

Fixes #4044ClaudeIntegration.inject_argument_hint spliced argument-hint: "..." in as a raw text line immediately after the first line starting with description:. That's safe for a short, single-line description, but when a description is long enough for the YAML dumper to fold it across multiple indented continuation lines, the splice landed inside that scalar instead of after it:

  • Plain (unquoted) folded scalar → invalid YAML (yaml.parser.ParserError).
  • Quoted folded scalar → parses, but argument-hint doesn't exist as a key — its line is silently absorbed into the description string.

This is the case #3996 didn't cover: bundled core commands carry no argument-hint in their source frontmatter, so CommandRegistrar.apply_argument_hint's structural inheritance path is a no-op for them, and this raw-text fallback in post_process_skill_content is what actually runs for every core Claude skill.

Fix

inject_argument_hint now skips past every continuation line of the description scalar (anything more indented than the description: key itself — this covers both plain and quoted folded styles) before inserting argument-hint:, so the new key always lands after the whole scalar ends rather than in the middle of it. No change to the injected line's format (argument-hint: "<hint>"), so short, non-folding descriptions behave exactly as before.

Test plan

Added two regression tests in tests/integrations/test_integration_claude.py::TestClaudeArgumentHints that build frontmatter with a ~150+ char description via yaml.safe_dump (reproducing the fold from the issue) for both the plain and forced-quoted cases, run it through inject_argument_hint, and assert the result is valid YAML with argument-hint present as its own key and description unchanged.

Confirmed both new tests fail against the pre-fix code with exactly the two failure modes from the issue:

FAILED test_inject_argument_hint_survives_folded_description
  yaml.parser.ParserError: while parsing a block mapping
  ... expected <block end>, but found '<scalar>'

FAILED test_inject_argument_hint_survives_quoted_folded_description
  KeyError: 'argument-hint'

With the fix:

tests/integrations/test_integration_claude.py .......................... [ 61%]
................                                                         [100%]
============================== 42 passed in 1.35s ==============================

Full suite (pytest tests -q): 6786 passed, 9 skipped, 10 failed — all 10 failures reproduce identically on unmodified main (composed-template python/shell parity and a rich-markup width assertion, unrelated to this change and to the Claude integration).

ruff check on both changed files reports the same 17 pre-existing findings as on unmodified main; none introduced by this diff.

AI assistance disclosure

This PR was written by an autonomous AI coding agent (Claude, via an agent harness), including the diagnosis, fix, and regression tests. It was validated by running the reproduction from the issue, the existing and new test suites, and by confirming pre-existing failures reproduce unmodified on main.

…tions

ClaudeIntegration.inject_argument_hint spliced argument-hint: "..." as a
raw text line right after the first line starting with "description:".
When a description is long enough for the YAML dumper to fold it across
indented continuation lines, that splice landed inside the scalar,
producing invalid YAML (plain scalar) or silently absorbing the hint
into the description string (quoted scalar). This reproduces github#3991 for
the case github#3996 didn't cover: bundled core commands have no argument-hint
in their source frontmatter, so the structural apply_argument_hint path
is a no-op and this raw-text fallback is what actually runs.

Skip every continuation line of the description scalar (anything more
indented than the key itself) before inserting, so the new key always
lands after the whole scalar ends rather than in the middle of it.

Fixes github#4044

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.

Pull request overview

Fixes Claude skill frontmatter corruption when descriptions wrap across YAML lines.

Changes:

  • Skips indented description continuation lines before injecting argument-hint.
  • Adds regression tests for plain and quoted folded descriptions.
Show a summary per file
File Description
src/specify_cli/integrations/claude/__init__.py Makes hint injection fold-aware.
tests/integrations/test_integration_claude.py Tests folded description handling.

Review details

Tip

Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

i += 1
# Skip past folded/quoted continuation lines of the scalar
# before inserting, so the new key lands after it ends.
while i < n and lines[i][:1] in (" ", "\t"):
PyYAML serializes an embedded paragraph break ("\n\n") inside a quoted
description as unindented blank lines, not indented continuation
lines. inject_argument_hint only skipped indented lines, so it still
inserted argument-hint mid-scalar for multi-paragraph descriptions,
reproducing the github#4044 failure modes. Skip blank lines too, and add a
regression test for the multi-paragraph case.
@chelsealong

Copy link
Copy Markdown
Contributor Author

Fixed: inject_argument_hint now also treats unindented blank lines as continuation lines, since PyYAML emits those for an embedded \n\n inside a quoted description scalar. Added test_inject_argument_hint_survives_multi_paragraph_description, which reproduces the absorbed-key failure on the prior fix and passes now.

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

Labels

None yet

Projects

None yet

3 participants