Skip to content

Quote in a heredoc body, comment or prose hides a later command line from the command-word scan #813

Open

Description

@elliottwaves-20

Summary

On main (checked at 5edc347), a double quote in a heredoc body, a shell comment or Markdown prose can pair with a quote on a later command line. _has_shell_command_word_exhaustion then parses one word across those lines and moves parsed_through past it, so every candidate inside the word is skipped. That includes a runtime-selected command with destructive operands, and the file is reported as completely inspected with no TM1.

I first mentioned this class in #780, which is now closed.

Reproducers

Each of these returns False from has_bounded_parse_exhaustion(..., file_type="shell", complete_context=True) on main. They also return False when padded with 400 ordinary comment lines.

# x "
$CMD"" -rf / # "
cat <<E
he said "hi
E
$CMD"" -rf / # "

Further variants of the same shape: the heredoc line can be <<'E' with a quoted delimiter, or one of "${X}, "${X}" ", "$(date)$()"e" or "`date`$()"". The heredoc case also reproduces with lone-CR line endings.

The same happens in Markdown when a prose quote pairs into a fenced block (file_type="markdown"):

Run "a
```sh
$CMD"" -rf / # "
```

At scan level, run_static_patterns_with_ledger records this run.sh as COMPLETED:

#!/bin/sh
CMD="${TOOL:-rm}"
cat <<EOF
he said "hi
EOF
$CMD"" -rf / --no-preserve-root # done "

sh runs rm -rf / --no-preserve-root there. The heredoc body is data, so its quote never pairs with anything.

Cause

parsed_through advances to the end of any successfully parsed, non-dynamic word, and that includes a word whose quoted span crosses line breaks. The scan has no heredoc or comment state, so it cannot tell that the opening quote is not a shell quote. Comment-confined words already lose quote ownership (confined_word), but they still move parsed_through.

Proposed fix

I'd like to open a PR. It does not try to prove quote state. It only stops a multi-line word from hiding later command lines:

  • A word that spans a line break (LF or lone CR) opens a shadow region instead of moving parsed_through.
  • Candidates inside the region are still parsed and checked, but only at a command position (line start, or after ;, |, & or (). They never own quotes and never move the frontier, and an unresolved parse inside the region is not charged to the command-word budget.
  • Python sources keep the current frontier, because python_source already proves their string and comment bounds.

Later candidates are therefore the same as on main. The change can only add checks, so no file can move from partial to complete. On a local corpus of about 3,600 skill files, the reproducers above and their variants become partial. 4 previously complete files become partial: Markdown with prose quotes pairing across lines. No file becomes complete. The existing parse-work bound tests (test_json_owned_runtime_bounds.py) still pass.

Would a PR along these lines be welcome?

Activity

  1. elliottwaves-20 commented on Oct 9, 2026

    @elliottwaves-20
    ContributorAuthor

    Opened #814 with the fix described above.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions