Skip to content

Commit 0805674

Browse files
author
bgagent
committed
fix(workflows): repo-bound task w/o workflow_ref → coding/new-task-v1, not default/agent-v1
aws-samples#296 (workflow-driven tasks) replaced the task_type→workflow mapping with a resolution ladder, but left the repo-aware rung ('Phase 4') unwired. Every task with no explicit workflow_ref — all Slack tasks and all aws-samples#247 orchestration children (neither sets one) — fell through to the platform default default/agent-v1: the freeform, repo-less agent prompt with NO git/PR discipline. The agent then improvised (gh api / gh pr create against an empty local clone), so ensure_pr found no commits and recorded pr_url=null, screenshot→Linear routing lost its branch signal, and aws-samples#247 A4 stacking broke (children couldn't fetch the unpushed predecessor branch). Re-wire the missing rung minimally: resolveWorkflowRef takes hasRepo; an absent ref with a repo present resolves to coding/new-task-v1 (the disciplined coding workflow — edit locally, commit, push, platform opens the PR via ensure_pr), matching pre-aws-samples#296 behaviour. Repo-less tasks still default to default/agent-v1. An explicit workflow_ref always wins. The single create-task-core call site passes Boolean(body.repo), so both Slack and orchestration (which create via createTaskCore with repo set) inherit the fix. Upstream regression — worth an upstream issue too. Updated workflows + create-task-core tests; the old test asserting default/agent-v1 for a repo task encoded the regression.
1 parent 603a554 commit 0805674

4 files changed

Lines changed: 47 additions & 8 deletions

File tree

cdk/src/handlers/shared/create-task-core.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,11 @@ export async function createTaskCore(
116116
if (!isValidWorkflowRef(body.workflow_ref)) {
117117
return errorResponse(400, ErrorCode.VALIDATION_ERROR, 'Invalid workflow_ref. Expected "<domain>/<name>-vN[@<constraint>]".', requestId);
118118
}
119-
const resolvedWorkflow = resolveWorkflowRef(body.workflow_ref);
119+
// Pass whether the request carries a repo: a repo-bound task with no
120+
// explicit workflow_ref resolves to coding/new-task-v1 (the disciplined
121+
// coding workflow), not the repo-less default/agent-v1 (#296 regression —
122+
// see resolveWorkflowRef rung 3a).
123+
const resolvedWorkflow = resolveWorkflowRef(body.workflow_ref, Boolean(body.repo));
120124
if (resolvedWorkflow === null) {
121125
// Distinguish an unknown id from an unsatisfiable @version pin so the caller
122126
// learns which it is (#296 finding #6 — a bad pin no longer silently runs

cdk/src/handlers/shared/workflows.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,32 @@ export type WorkflowResolutionError = 'unknown_id' | 'unsatisfiable_version';
180180
* resolution ladder (WORKFLOWS.md §"Replacing task types"):
181181
* 1. explicit ``workflow_ref`` (id + optional ``@constraint``);
182182
* 2. (Blueprint default — Phase 4, not yet wired);
183-
* 3. the platform default ``default/agent-v1``.
183+
* 3a. no explicit ref BUT a repo is present ⇒ the coding default
184+
* ``coding/new-task-v1`` (a repo-bound task is a coding task);
185+
* 3b. otherwise the repo-less platform default ``default/agent-v1``.
186+
*
187+
* Rung 3a restores the pre-#296 behaviour: before workflow-driven tasks, a
188+
* task with a repo and no explicit type ran as ``new_task`` →
189+
* ``coding/new-task-v1`` (edit locally, commit, push, platform opens the PR
190+
* via ``ensure_pr``). #296 introduced the resolution ladder but left the
191+
* repo-aware rung unwired, so every repo task fell through to
192+
* ``default/agent-v1`` — the freeform repo-less agent prompt with no git/PR
193+
* discipline — which broke PR-url reporting, screenshot→issue routing, and
194+
* #247 stacking (the agent improvised ``gh api``/``gh pr create`` against an
195+
* empty local clone). ``hasRepo`` re-wires that rung minimally until the
196+
* Blueprint router (Phase 4) lands. Callers WITHOUT an explicit ref pass
197+
* whether the request carries a repo.
184198
*
185199
* Returns ``null`` when an explicit ref cannot be resolved — either the id is
186200
* unknown OR an ``@constraint`` pins a version the platform does not ship. The
187201
* constraint is NO LONGER silently discarded (PR review #296 finding #6): a pin
188202
* like ``coding/new-task-v1@2.0.0`` fails admission rather than quietly running
189203
* ``1.0.0``. Use {@link resolveWorkflowRefError} for which case, to craft the 400.
190204
*/
191-
export function resolveWorkflowRef(ref?: string | null): ResolvedWorkflow | null {
205+
export function resolveWorkflowRef(ref?: string | null, hasRepo = false): ResolvedWorkflow | null {
192206
if (ref === undefined || ref === null || ref === '') {
193-
const fallback = DESCRIPTORS[DEFAULT_WORKFLOW_ID];
207+
const fallbackId = hasRepo ? 'coding/new-task-v1' : DEFAULT_WORKFLOW_ID;
208+
const fallback = DESCRIPTORS[fallbackId];
194209
return { id: fallback.id, version: fallback.version };
195210
}
196211
const { id, constraint } = parseWorkflowRef(ref);

cdk/test/handlers/shared/create-task-core.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,16 +523,19 @@ describe('createTaskCore', () => {
523523
expect(result.statusCode).toBe(201);
524524
});
525525

526-
test('resolves the default workflow when workflow_ref is omitted', async () => {
526+
test('resolves the coding workflow when workflow_ref is omitted AND a repo is present', async () => {
527527
const result = await createTaskCore(
528528
{ repo: 'org/repo', task_description: 'Fix the bug' },
529529
makeContext(),
530530
'req-default',
531531
);
532532
expect(result.statusCode).toBe(201);
533533
const body = JSON.parse(result.body);
534-
// No workflow_ref ⇒ the resolution ladder falls to the platform default.
535-
expect(body.data.resolved_workflow).toEqual({ id: 'default/agent-v1', version: '1.0.0' });
534+
// No workflow_ref BUT a repo is present ⇒ the repo-aware fallback resolves
535+
// to the disciplined coding workflow, not the repo-less default/agent-v1.
536+
// (Pre-#296 behaviour; #296 left this rung unwired and every repo task
537+
// fell through to default/agent-v1, breaking pr_url/screenshot/stacking.)
538+
expect(body.data.resolved_workflow).toEqual({ id: 'coding/new-task-v1', version: '1.0.0' });
536539
});
537540

538541
test('creates a pr-iteration workflow task with pr_number', async () => {

cdk/test/handlers/shared/workflows.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,27 @@ describe('resolveWorkflowRef', () => {
7272
expect(resolveWorkflowRefError(undefined)).toBeNull();
7373
});
7474

75-
test('falls back to the platform default when ref is absent', () => {
75+
test('falls back to the repo-less platform default when ref is absent AND no repo', () => {
7676
expect(resolveWorkflowRef(undefined)).toEqual({ id: DEFAULT_WORKFLOW_ID, version: '1.0.0' });
7777
expect(resolveWorkflowRef(null)).toEqual({ id: DEFAULT_WORKFLOW_ID, version: '1.0.0' });
7878
expect(resolveWorkflowRef('')).toEqual({ id: DEFAULT_WORKFLOW_ID, version: '1.0.0' });
79+
// explicit hasRepo=false is the same as omitting it
80+
expect(resolveWorkflowRef(undefined, false)).toEqual({ id: DEFAULT_WORKFLOW_ID, version: '1.0.0' });
81+
});
82+
83+
test('falls back to coding/new-task-v1 when ref is absent BUT a repo is present (#296 regression fix)', () => {
84+
// A repo-bound task with no explicit workflow_ref is a coding task — it must
85+
// get the disciplined coding workflow (edit/commit/push, platform ensure_pr),
86+
// NOT the freeform repo-less default/agent-v1 that broke pr_url/screenshot/stacking.
87+
expect(resolveWorkflowRef(undefined, true)).toEqual({ id: 'coding/new-task-v1', version: '1.0.0' });
88+
expect(resolveWorkflowRef(null, true)).toEqual({ id: 'coding/new-task-v1', version: '1.0.0' });
89+
expect(resolveWorkflowRef('', true)).toEqual({ id: 'coding/new-task-v1', version: '1.0.0' });
90+
});
91+
92+
test('an EXPLICIT ref is honored regardless of hasRepo (repo-less workflow against a repo)', () => {
93+
// hasRepo only steers the absent-ref fallback; an explicit ref always wins.
94+
expect(resolveWorkflowRef('default/agent-v1', true)).toEqual({ id: 'default/agent-v1', version: '1.0.0' });
95+
expect(resolveWorkflowRef('knowledge/web-research-v1', true)).toEqual({ id: 'knowledge/web-research-v1', version: '1.0.0' });
7996
});
8097

8198
test('returns null for an unknown but well-formed ref', () => {

0 commit comments

Comments
 (0)