Skip to content

Malformed createGitHubStep (missing name/action, stray command) breaks every PR-shipping generated workflow #144

@kjgbot

Description

@kjgbot

Summary

Every PR-shipping spec generates a malformed createGitHubStep(...) call that throws at workflow startup, blocking the whole workflow. Confirmed on ricky 0.1.81 across NightCTO persona-migration specs 040, 041, 042 (auto-skipped after 2 strikes) and 050 (verified will fail identically). All 6 remaining persona-migration specs are blocked by this one bug.

The error

Error: GitHub step requires a non-empty name
    at validateGitHubStepConfig (@agent-relay/github-primitive/dist/workflow-step.js:131)
    at createGitHubStep (...:24)
    at main (workflows/generated/ricky-040-relayfile-acl-scope-...ts)
node --experimental-strip-types exited with code 1

Surfaces to the runner as the opaque Local runtime could not execute the workflow: node ... exited with code 1 blocker → the spec fails, retries, fails again, gets skipped. The agent never even starts.

Root cause: LLM emits a createGitHubStep with the wrong shape

The generated call mixes the GitHub primitive with a deterministic shell-step shape:

createGitHubStep({
  dependsOn: ['push-branch'],
  command: [                       // ← createGitHubStep has NO `command` field
    'BRANCH=$(git rev-parse --abbrev-ref HEAD)',
    'gh pr create ...',
  ],
  // ← no `name`, no `action`
})

createGitHubStep requires name and action (validateGitHubStepConfig, @agent-relay/github-primitive/dist/workflow-step.js:129). This call has neither and instead carries a command array as if it were a { type: 'deterministic', command } step. So it throws at construction, before any step runs.

The model clearly wanted a deterministic gh pr create step but wrapped it in createGitHubStep. Two valid shapes it should have used instead:

// (a) deterministic shell step
.step('ship-pr', { type: 'deterministic', dependsOn: ['push-branch'], command: "gh pr create ..." })
// (b) the real primitive
.step('ship-pr', createGitHubStep({ name: 'ship-pr', action: 'createPR', repo: 'owner/repo', params: { title, head, base, body }, dependsOn: ['push-branch'] }))

Why ricky doesn't catch it

workforce-persona-writer.ts:1467-1478 validates that a PR-shipping spec references createGitHubStep/GitHubStepExecutor/@agent-relay/github-primitive — a presence check — but never validates the call is well-formed. A malformed createGitHubStep satisfies the presence regex, passes generation, and only explodes at runtime.

This is the same class as the skill-boundary gate bug (#141): a generation defect that only surfaces as an opaque runtime exit 1.

Proposed fix

  1. Generation guidance (workforce-persona-writer.ts writer task / bundled writing-agent-relay-workflows SKILL.md): show the two correct PR-shipping shapes explicitly and state that createGitHubStep takes name + action + params and never a command array; a gh pr create shell line must be a type:'deterministic' step, not wrapped in createGitHubStep.
  2. Static validation at generation time (best — fail loud, not at runtime): in the artifact validator, parse createGitHubStep({...}) calls and assert each has a non-empty name and a valid action, and has no command key. Emit a blocking INVALID_GITHUB_STEP generation issue so the pre-write repair loop fixes it before the workflow is written — instead of the agent discovering it at launch.
  3. Map the github-primitive requires a non-empty name throw to a specific blocker code in the runtime failure classifier so it's not an opaque exit 1.

Impact / priority

Release-blocking for any spec that ships a PR — which is most implementation specs. In this run it silently skipped 3 specs and would have skipped 3 more. The skip-after-2 safety net kept the run from hanging, but the work just didn't get done.

Repro

nightcto persona-migration 040-relayfile-acl-scope: ricky local --spec-file specs/persona-migration/040-relayfile-acl-scope.md --run → generates workflows/generated/ricky-040-*.tsnode --experimental-strip-types that file → Error: GitHub step requires a non-empty name.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions