aws-samples / aws-samples/sample-collaborative-ai-dlc
Recompose can relaunch from an earlier stage excluded by the original projection
- Dominant language
- JavaScript
- Stars
- 75
- Forks
- 23
- Avg merge
- 3d 17h
- Merged PRs (30d)
- 24
Description
## Summary
`POST /projects/{projectId}/intents/{intentId}/recompose` freezes history only for stages that already have execution rows. A stage excluded from the original projection has no row, so an earlier stage can be changed from `SKIP` to `EXECUTE` and the run relaunches from that stage.
This was identified while reviewing #435. The frontend now clamps locked values before submitting, but the invariant remains unenforced by the backend and can still be bypassed by a direct API call or another client.
## Reproduction
1. Define an `ideation` stage before the current execution boundary and exclude it from the original `feature` projection.
2. Seed a parked run with `analyze: SUCCEEDED` and `optional: WAITING_FOR_HUMAN`. There is no execution row for `ideation`.
3. Submit a recompose grid containing:
```json
{
"ideation": "EXECUTE",
"analyze": "EXECUTE",
"optional": "EXECUTE",
"build": "SKIP"
}
```
A diagnostic backend test expecting `409` receives `202`, and the run is eligible to relaunch from `ideation`.
## Expected behavior
The server rejects the request with `409` because `ideation` is before the run progress boundary. Reshaping historical stages should require rewind.
## Actual behavior
The request is accepted with `202`. Frozen-state validation iterates only over `records.stages`, so the excluded stage is invisible to the check.
The in-flight composer has the same gap: its `frozenGrid` is also derived solely from execution rows. It may therefore produce a proposal that is valid according to composer validation but violates the intended progress boundary.
## Acceptance criteria
- Derive the canonical frozen boundary server-side from the compiled workflow/current plan and run progress, including stages with no execution row.
- Reject recomposed grids that add or alter stages before that boundary.
- Pass the same canonical frozen grid/boundary to in-flight composer validation.
- Add backend tests covering an earlier, originally excluded stage with no execution row for both `/recompose` and in-flight compose.
- Keep frontend locking as a UX guard, not as the enforcement boundary.
Contributor guide
Research direction
Start with the backend handler and validation for POST /projects/{projectId}/intents/{intentId}/recompose, then trace how records.stages and the in-flight composer derive frozenGrid. Use the compiled workflow/current plan and run progress to define the shared boundary, and add backend coverage for an excluded earlier stage with no execution row in both paths. Done means both requests reject the invalid grid with 409 while valid recompositions continue to work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- api, backend, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100