Skip to content

Lint five manifest mistakes that kept costing worker attempts - #157

Open
Poncho1112 wants to merge 1 commit into
NateBJones-Projects:mainfrom
Poncho1112:pr/lint-footguns
Open

Poncho1112 wants to merge 1 commit into
NateBJones-Projects:mainfrom
Poncho1112:pr/lint-footguns

Conversation

@Poncho1112

Copy link
Copy Markdown

Five lint rules, each from a manifest mistake that burned real worker attempts in one operator's runs. They were recorded at the time, and each one kept recurring because nothing caught it before spawn.

Rule What it catches What it cost
Claude list flag swallows the spec a claude task whose engine_args end on --allowedTools, --add-dir, --disallowedTools, --mcp-config, ... the spec Ringer appends after {engine_args} becomes one more list value; every attempt, retry included, dies in seconds with Input must be provided either through stdin or as a prompt argument
Unbalanced quote shlex.split(check) fails (heredocs are skipped) an apostrophe inside a single-quoted bash -c '...' ends the string early; the check dies with a syntax error against correct work
Codex writable_roots a codex task (non-worktree) whose expect_files are absolute paths outside its task directory, with no writable_roots in engine_args the sandbox refuses the write; the worker stages the output in its task dir and the run FAILs
Collapsed untracked dirs git status --porcelain/--short without --untracked-files=all git reports a new directory as one dir/ line, so file-level ownership checks fail honest work
Bash-only syntax under /bin/sh pipefail, [[, <<< outside a quoted bash -c argument checks run through /bin/sh (dash on Debian/Ubuntu): set: Illegal option -o pipefail

About rule 1 and the README. The README already says "Watch for variadic CLI flags… put {spec} before that flag" for args_template. This rule catches the same hazard when it arrives through a task's engine_args.

  • lint only sees the manifest, so it warns and offers both fixes: the = form, or an args_template with {spec} first.
  • validate_manifest_engines has the config, so run refuses the task only when that engine's args_template puts {spec} after {engine_args}, which is when the swallow really happens. An engine set up the way the README recommends runs normally.
  • The README paragraph gains one sentence describing this.

All other findings are warnings, like the existing lint output.

Tests

  • tests/test_lint_footguns.py has 12 tests covering each rule's positive case and the look-alikes that must stay quiet: the = form, a later scalar flag such as --effort max, other engines, a quoted heredoc containing an apostrophe, writable_roots given, relative or in-task paths, worktrees mode, -uall, and bash -c wrapping. It also covers run refusing before any worker starts when the order is fatal, and proceeding when it isn't.
  • RINGER_NO_SELF_UPDATE=1 python3 -m unittest discover -s tests passes all 296 tests.

This is independent of #154, #155 and #156.

🤖 Generated with Claude Code

Each rule comes from a mistake that cost real worker attempts in one
operator's runs, recorded when it happened:
- a Claude task whose engine_args end on a list flag (--allowedTools,
  --add-dir, ...) swallows the spec Ringer appends after engine_args, and
  every attempt dies in seconds with "Input must be provided either through
  stdin or as a prompt argument". lint warns and offers the `=` form or the
  README's argument order. `run` refuses the task only when the engine's
  args_template puts {spec} after {engine_args}, which is when the swallow
  actually happens;
- a check with an unbalanced quote (an apostrophe ending a single-quoted
  bash -c string early); heredocs are skipped;
- a codex task whose expect_files sit outside its task directory with no
  writable_roots;
- `git status --porcelain` without --untracked-files=all, which collapses an
  untracked directory into one line and breaks ownership comparisons;
- bash-only syntax (pipefail, [[, <<<) in a check that runs under /bin/sh,
  outside a quoted bash -c argument.

The README's variadic-flags paragraph now mentions the per-task case.

Tests: tests/test_lint_footguns.py (12) covers each rule, the look-alikes
that must stay quiet, and run refusing or proceeding by args_template
order. Full suite: 296 tests, all passing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.

1 participant