Conversation
JWThewes
left a comment
There was a problem hiding this comment.
The overall approach is sensible: reusing the existing HUMAN/STAGE/UNIT lifecycle and native exporter keeps the feature's scope manageable. I am requesting changes for the five reproduced correctness and lifecycle issues in the inline comments: submission races, runtime routing, parallel export isolation, retry identity, and retained construction capacity.
Validation against a7823eb: 727 existing tests passed across focused backend/frontend suites, including exporter and durable replay checks; frontend type checking passed. Five additional local reproduction tests fail on the reported issues. These were local checks, not a deployed end-to-end run.
| acceptedAt, | ||
| acceptedBy: responder.sub, | ||
| }; | ||
| const answered = await store.acceptExternalDevelopment({ |
There was a problem hiding this comment.
[P1] Claim submission ownership before importing
The acceptance CAS runs after import-handoff-artifacts has already changed the lane checkout and canonical artifacts. Two submissions can both pass updateExternalDevelopment while the task is pending. If submission A pauses before import, B can import and be accepted, then A can overwrite B's artifacts before its own acceptance returns 409. Downstream execution has already been resumed with B's accepted metadata.
I reproduced this by holding A's import until B completed: B returned 200, A returned 409, and the live code-summary hash matched A while the accepted task recorded B. Please claim exclusive submission ownership before any checkout/artifact mutation and enforce that ownership throughout import and acceptance, including against cancellation.
| agentRuntimeArn: AGENTCORE_RUNTIME_ARN(), | ||
| runtimeSessionId: laneSessionIdFor(intentId, gate.sectionIndex, gate.unitSlug), |
There was a problem hiding this comment.
[P1] Use the intent's saved runtime target for handoff imports
This invocation uses the fallback runtime ARN and omits the saved environment endpoint. Normal stage execution resolves meta.environment through the shared runtime-target helper. For an intent using a managed environment, the import can therefore update a different runtime's checkout while downstream stages resume in the original environment with its existing checkout.
A reproduction with a saved managed runtime and revision_r_7 endpoint still invoked the default ARN without a qualifier. Please use runtimeTargetInput(meta, AGENTCORE_RUNTIME_ARN()) here and base the configuration check on that resolved target as well.
| .filter( | ||
| (task) => | ||
| task?.status === 'pending' && | ||
| !(mode === 'unit-handoff' && task.humanTaskId === handoffTaskId), | ||
| ) | ||
| .map((task) => task.stageId ?? stageIdByInstance.get(task.stageInstanceId)) |
There was a problem hiding this comment.
[P2] Scope pending gates to the selected handoff unit
This filter removes the selected task but retains pending tasks from sibling units, then collapses them to the shared stage ID. When two independent units are parked for external code generation, the sibling task adds code-generation to awaitingGateStageIds. The selected unit's stage is consequently marked ?, and the later requirement that its marker be - rejects the export with "handoff code-generation stage is not active". Both handoffs can block each other's downloads.
I reproduced this with two pending unit handoffs; removing only the sibling task made the same export succeed. Please scope gate projection by the selected unit/stage instance and section.
| const attempt = Number(prior?.attempt ?? 0); | ||
| const humanTaskId = `external-s${sectionIndex}-${unitSlug}-a${attempt}`; |
There was a problem hiding this comment.
[P2] Give a fresh handoff a distinct identity on lane retry
The task ID contains the persisted stage attempt but no lane retry identity. The existing halt-and-ask retry creates a new lane context while preserving that attempt. After an external handoff succeeds and a later stage or merge fails, choosing external development again therefore reuses the already-answered task. Task creation fails and is swallowed, then setGateCallbackId rejects the answered row and the lane fails with gate_callback_conflict.
I reproduced a successful handoff followed by a second handoff at the preserved attempt: the second failed at callback binding. Please distinguish fresh handoffs across lane retries while keeping replay of the same handoff idempotent.
| if (!answeredEarly) { | ||
| await ctxArg | ||
| .step(`external-release-${humanTaskId}`, () => stopSession(sessionId)) | ||
| .catch(() => {}); | ||
| await callbackPromise; |
There was a problem hiding this comment.
[P2] Release construction capacity while external development is parked
Stopping the runtime session does not release the semaphore permit acquired by runLaneBody. The lane holds that permit throughout this potentially long external-development wait. With maxParallelUnits = 1, an independent unit in the same wave cannot even initialize until the external handoff finishes; with larger limits, queued independent work is blocked once all permits are occupied by handoffs. This contradicts the intended unit-local pause and the existing release of construction capacity during PR review waits.
I reproduced this with a completed skeleton and two independent remaining units: the second unit started only after the first handoff was accepted. Please release the permit while parked and reacquire it before managed execution resumes.
Important
This PR replaces #407 It is based directly on current
mainand preserves the reviewed external-handoff work without the previous branch-history issues.Summary
This PR adds an additional native workspace export mode for one Construction unit: code-generation only, with workflow continuation in Collaborative AI-DLC.
When a non-autonomous unit reaches the existing validation gate immediately before
code-generation, the developer can either:another preferred environment.
The second option parks only that unit lane. Independent lanes and the overall intent remain running. The developer downloads a native AI-DLC workspace scoped to the selected unit, pushes changes to the existing unit branch, then submits the native
code-generation-planandcode-summary. Collaborative AI-DLC validates and imports the result, completes the parkedcode-generationstage, and resumes the normal cloud workflow.What changed
Construction gate and handoff
code-generation.HUMAN#,STAGE#, andUNIT#lifecycle instead of adding a separate handoff state machine.Unit-scoped native export
unit-handoffprojection mode on top of the exporter from feat: export native AI-DLC workspaces #403.code-generationstage is parked on the current external-development task.code-generationstage. Later stages remain cloud-owned and run after the handoff is accepted.workflow-continuationexports unchanged.Submission and workflow continuation
code-generation-plan.mdandcode-summary.md.Relationship to #324
This PR implements a practical first slice of #324 using the workflow and exporter infrastructure that already exists. It intentionally does not implement the RFC's full session platform.
Implemented
Not implemented in this PR
For these reasons, this PR only references #324 (but does not close it).
Verification
Related to #324.