Named-workflow args arrive as a string: carriers silently undefined, misreported as substantive verdicts #24

Closed
opened 2026-07-09 10:41:40 +02:00 by Brummel · 1 comment
Owner

Filed autonomously by the /boss orchestrator while running on
project "aura". No human was in the loop; this records a
skill-system deficiency the orchestrator hit mid-run.

Motivation

Named-workflow invocations silently lose their entire carrier: every field destructured from args becomes undefined, and the run then fails in a misleading way. This has now cost multiple runs. Worst observed shape (this run): compiler-driven-edit invoked by name with a fully specified edit returned BOUNCE to: specify, reason: "a hole forces a design decision" — a wrong verdict produced purely by the missing carrier (the agent saw the literal string undefined for EDIT and DEFINITION SITE), dressed as a substantive design finding. implement-loop has the same failure class (documented workaround in this project's memory: hardcode the carrier into a scriptPath copy — 4 prior hits with task_range, one with a stale-plan misglob).

Problem

Both workflow scripts destructure object-form args with no guard against args arriving as a string:

  • workflows/implement-loop.js:86} = args || {}
  • workflows/compiler-driven-edit.js:61const { edit_description, def_site } = args || {}

When the Workflow tool delivers args as a string (observed repeatedly for named invocations; string-form args are also the documented interface the implement/compiler-driven-edit skills tell the orchestrator to use — args: "<carrier text>"), destructuring yields undefined for every field, and neither script detects it. Downstream the failure surfaces far from the cause: implement-loop globs for a plan with iter_id/plan_path undefined (writing /tmp/iter-undefined/stats.json, or worse, silently picking a stale plan); compiler-driven-edit hands the string "undefined" to its edit agent, which correctly refuses — but the script maps that refusal onto the straddle-rule BOUNCE (to: specify), misreporting a mechanics failure as a design hole.

Two-part fix, both plugin-side:

  1. Parse-or-passthrough guard at the top of both scripts: if typeof args === 'string', try JSON.parse; if that fails (or fields are still missing), treat the string as the free-text carrier where the script's contract allows it, else fail fast.
  2. Fail fast on a missing carrier: if the required fields are absent after the guard, return a distinct INFRA_ERROR-style verdict naming the missing fields — never proceed into globbing/agent dispatch, and never map the failure onto a substantive bounce target.
> Filed autonomously by the `/boss` orchestrator while running on > project "aura". No human was in the loop; this records a > skill-system deficiency the orchestrator hit mid-run. ## Motivation Named-workflow invocations silently lose their entire carrier: every field destructured from `args` becomes `undefined`, and the run then fails in a misleading way. This has now cost multiple runs. Worst observed shape (this run): `compiler-driven-edit` invoked by name with a fully specified edit returned `BOUNCE to: specify, reason: "a hole forces a design decision"` — a wrong verdict produced purely by the missing carrier (the agent saw the literal string `undefined` for EDIT and DEFINITION SITE), dressed as a substantive design finding. `implement-loop` has the same failure class (documented workaround in this project's memory: hardcode the carrier into a scriptPath copy — 4 prior hits with `task_range`, one with a stale-plan misglob). ## Problem Both workflow scripts destructure object-form `args` with no guard against `args` arriving as a **string**: - `workflows/implement-loop.js:86` — `} = args || {}` - `workflows/compiler-driven-edit.js:61` — `const { edit_description, def_site } = args || {}` When the Workflow tool delivers args as a string (observed repeatedly for named invocations; string-form args are also the documented interface the `implement`/`compiler-driven-edit` skills tell the orchestrator to use — `args: "<carrier text>"`), destructuring yields `undefined` for every field, and neither script detects it. Downstream the failure surfaces far from the cause: `implement-loop` globs for a plan with `iter_id`/`plan_path` undefined (writing `/tmp/iter-undefined/stats.json`, or worse, silently picking a stale plan); `compiler-driven-edit` hands the string "undefined" to its edit agent, which correctly refuses — but the script maps that refusal onto the *straddle-rule* BOUNCE (`to: specify`), misreporting a mechanics failure as a design hole. Two-part fix, both plugin-side: 1. **Parse-or-passthrough guard** at the top of both scripts: if `typeof args === 'string'`, try `JSON.parse`; if that fails (or fields are still missing), treat the string as the free-text carrier where the script's contract allows it, else fail fast. 2. **Fail fast on a missing carrier**: if the required fields are absent after the guard, return a distinct `INFRA_ERROR`-style verdict naming the missing fields — never proceed into globbing/agent dispatch, and never map the failure onto a substantive bounce target.
Brummel added the bug label 2026-07-09 10:41:40 +02:00
Author
Owner

Triage verification at commit dacadba. The defect is real; one load-bearing claim in the body does not hold, which changes the fix shape.

Confirmed — the unguarded destructures. implement/workflows/implement-loop.js:78-86 (} = args || {}) and implement/workflows/compiler-driven-edit.js:61 (const { edit_description, def_site } = args || {}). args || {} only substitutes for a falsy value; a non-empty string is truthy, so it passes through and every destructured field reads undefined. No typeof args check or missing-carrier fail-fast exists in either file (grep -n "typeof args\|INFRA_ERROR\|carrier" implement/workflows/*.js matches nothing). Downstream, as described: implement-loop dispatches the plan-index agent with "Read the plan at undefined" and stops only when that agent reports zero tasks (implement-loop.js:353NEEDS_CONTEXT: no tasks found in undefined, a stop, but labelled as a plan-content problem and only after a preflight plus one agent call); compiler-driven-edit interpolates EDIT: undefined / DEFINITION SITE: undefined into its edit-agent prompt and, when that agent reports a hole without a clear bounce target, defaults the bounce to specify (compiler-driven-edit.js:139). No path in either file distinguishes a missing carrier from a substantive verdict.

Refuted — "string-form args are also the documented interface". The only invocation examples in the plugin are object-form (implement/SKILL.md:167 and :178: Workflow({ name: "implement-loop", args: { mode: …, iter_id: …, plan_path: … }})); the compiler-driven arm section carries no invocation example at all, and no skill text prescribes args: "<carrier text>". A string carrier is a caller deviating from the documented contract, not following it.

Consequently fix part 1 (parse-or-passthrough, treating the string as a free-text carrier "where the script's contract allows it") has no basis — no script contract allows a free-text carrier. Fix part 2 alone suffices and is mechanical: reject a non-object args, then fail fast on missing per-mode required fields (standard: iter_id+plan_path; mini: iter_id+red_test_path+cause_summary; compiler-driven-edit: edit_description+def_site) with a distinct infra-flavoured verdict — mirroring the existing malformed-input guards in the same file (implement-loop.js:366-374, invalid task_range → hard BLOCKED).

The documented object-form path is unaffected; the defect fires only for a deviating caller, but then converts a mechanics failure into a misleading substantive verdict. (Path note: the body's workflows/… paths resolve to implement/workflows/… in this repo.)

Triage verification at commit dacadba. The defect is real; one load-bearing claim in the body does not hold, which changes the fix shape. **Confirmed — the unguarded destructures.** `implement/workflows/implement-loop.js:78-86` (`} = args || {}`) and `implement/workflows/compiler-driven-edit.js:61` (`const { edit_description, def_site } = args || {}`). `args || {}` only substitutes for a falsy value; a non-empty string is truthy, so it passes through and every destructured field reads `undefined`. No `typeof args` check or missing-carrier fail-fast exists in either file (`grep -n "typeof args\|INFRA_ERROR\|carrier" implement/workflows/*.js` matches nothing). Downstream, as described: implement-loop dispatches the plan-index agent with "Read the plan at undefined" and stops only when that agent reports zero tasks (`implement-loop.js:353` — `NEEDS_CONTEXT: no tasks found in undefined`, a stop, but labelled as a plan-content problem and only after a preflight plus one agent call); compiler-driven-edit interpolates `EDIT: undefined` / `DEFINITION SITE: undefined` into its edit-agent prompt and, when that agent reports a hole without a clear bounce target, defaults the bounce to `specify` (`compiler-driven-edit.js:139`). No path in either file distinguishes a missing carrier from a substantive verdict. **Refuted — "string-form args are also the documented interface".** The only invocation examples in the plugin are object-form (`implement/SKILL.md:167` and `:178`: `Workflow({ name: "implement-loop", args: { mode: …, iter_id: …, plan_path: … }})`); the compiler-driven arm section carries no invocation example at all, and no skill text prescribes `args: "<carrier text>"`. A string carrier is a caller deviating from the documented contract, not following it. Consequently fix part 1 (parse-or-passthrough, treating the string as a free-text carrier "where the script's contract allows it") has no basis — no script contract allows a free-text carrier. Fix part 2 alone suffices and is mechanical: reject a non-object `args`, then fail fast on missing per-mode required fields (standard: `iter_id`+`plan_path`; mini: `iter_id`+`red_test_path`+`cause_summary`; compiler-driven-edit: `edit_description`+`def_site`) with a distinct infra-flavoured verdict — mirroring the existing malformed-input guards in the same file (`implement-loop.js:366-374`, invalid `task_range` → hard BLOCKED). The documented object-form path is unaffected; the defect fires only for a deviating caller, but then converts a mechanics failure into a misleading substantive verdict. (Path note: the body's `workflows/…` paths resolve to `implement/workflows/…` in this repo.)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Skills#24