Skip to content

fix(api): dispatch-boundary guard rejects prose/markdown envelope (#581)#19

Open
miles990 wants to merge 1 commit into
mainfrom
fix/581-dispatch-prose-guard
Open

fix(api): dispatch-boundary guard rejects prose/markdown envelope (#581)#19
miles990 wants to merge 1 commit into
mainfrom
fix/581-dispatch-prose-guard

Conversation

@miles990

Copy link
Copy Markdown
Owner

Summary

Closes #581 (38-day phantom P0, id idx-af45d4ff-b34f-478e-a680-f3fe33bdaaf3).

bounded-shell-probe retry envelope is markdown + prose with a single bash line buried inside; api.ts was dispatching the whole envelope to bash -c → command-not-found storm → tripped freq≥2 in autonomy-closure-health.ts:315 → P0 re-surfaced forever.

This adds a dispatch-boundary regex guard in src/api.ts:315-323 that rejects payloads that look like prose/markdown (multi-line + non-shell tokens) before they hit the worker shell.

Files

  • src/api.ts +10 — guard regex + 400 response
  • tests/api.test.ts +8 — shell_received_prose test

Test plan

  • npx tsx --test --test-name-pattern="shell_received_prose" green locally
  • After merge: 5 cycles with zero new [worker:shell] FAIL ... line 0: <prose> lines → falsifier discharged

Verification

Full triage in .kuro/triage-581.md. Patch B (this PR) is the structural class-fix; Patch A (fix the retry generator upstream in mini-agent) is the orthogonal local-caller fix — either alone closes the symptom.

🤖 Generated with Claude Code

Shell worker received bounded-shell-probe retry envelopes (markdown with
'## Retry Task: ...' headings) and ran them through bash, producing
'command not found' storms that tripped the autonomy-closure freq counter.

Heuristic: first non-empty line starting with '##+ ' or '**Word' throws
shell_received_prose typed error — loud once, not silent-N-times.

ponytail: regex heuristic, upgrade to AST/allowlist if FPs appear.

Closes miles990/mini-agent#581

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a0f6ecbc2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/api.ts
Comment on lines +319 to +320
if (/^#{2,}\s+\S/.test(firstLine) || /^\*\*[A-Za-z]/.test(firstLine)) {
throw new Error(`shell_received_prose: shell worker received prose/markdown, not a command. first_line=${JSON.stringify(firstLine.slice(0, 120))}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Move prose validation ahead of task submission

Because this guard throws from executeWorker after /dispatch has already submitted and started a task, malformed shell input is treated as an execution failure rather than request validation: wait=true returns a 500 with a taskId, while the default async path returns 200 {status:"running"} and records the failure later. For callers using this endpoint as a dispatch-boundary check, the prose envelope is not rejected as a bad request and still pollutes task history/callback flow instead of producing the intended immediate 400-style validation error.

Useful? React with 👍 / 👎.

Comment thread src/api.ts
// ponytail: regex heuristic, upgrade to AST/allowlist if FPs appear.
{
const firstLine = shellCmd.split('\n').map(l => l.trim()).find(l => l.length > 0) ?? '';
if (/^#{2,}\s+\S/.test(firstLine) || /^\*\*[A-Za-z]/.test(firstLine)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allow valid shell comments before rejecting prose

This rejects any shell task whose first non-empty line is a double-hash comment, even though ## build is a valid bash comment and the legacy shell worker is documented/executed as a full bash string. A multiline task such as ## Run tests\nnpm test previously ran normally with the first line ignored by bash, but now fails with shell_received_prose before executing the real command.

Useful? React with 👍 / 👎.

Comment thread src/api.ts
// ponytail: regex heuristic, upgrade to AST/allowlist if FPs appear.
{
const firstLine = shellCmd.split('\n').map(l => l.trim()).find(l => l.length > 0) ?? '';
if (/^#{2,}\s+\S/.test(firstLine) || /^\*\*[A-Za-z]/.test(firstLine)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Catch top-level markdown headings too

The guard only recognizes headings with two or more # characters, so a prose envelope starting with a normal top-level markdown heading such as # Retry Task: foo still falls through to bash -c and produces the same command-not-found behavior this change is meant to stop. If this is intended as a dispatch-boundary markdown/prose guard, single-# headings need to be handled as well.

Useful? React with 👍 / 👎.

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