Skip to content

Separate scaffold workflow orchestration from CLI interaction #181

Description

@lloydrichards

What problem are we solving?

ScaffoldPipeline is the common CLI entry point for scaffolding, but it currently combines lifecycle orchestration with terminal-specific interaction and presentation.

Within one workflow it:

  • resolves Selection into Blueprint;
  • formats and renders Blueprint;
  • prompts for confirmation;
  • builds and formats Plan;
  • collects conflict decisions;
  • constructs and executes Apply;
  • prints ApplyResult counts;
  • previews and selects Finalize commands;
  • executes commands and renders output streams;
  • aggregates Finalize failures;
  • collects and renders next steps.
flowchart TD
  SP[ScaffoldPipeline]
  SP --> L[Lifecycle stages]
  SP --> P[Prompts and decisions]
  SP --> F[Terminal formatting]
  SP --> X[Process stream rendering]
  SP --> N[Next-step presentation]
  SP --> C[Failure policy]
Loading

The standalone plan command separately reconstructs part of the same workflow:

const blueprint = yield* blueprintService.resolve(selection);
const plan = yield* planService.build({ blueprint, repoRoot, config });
const scripts = yield* finalizeService.preview(blueprint, finalizeConfig);

Its error behavior differs: Finalize preview failures are converted to an empty list, while the interactive pipeline handles Finalize through another path. This gives the two consumers different interpretations of the same lifecycle.

The current pipeline also reaches back to Selection after Apply to infer workspace behavior, allowing upstream user intent to leak past Blueprint and Plan. Next steps are nested under the presence of Finalize scripts. These are signs that presentation flow, rather than lifecycle results, determines what downstream information is available.

Repository configuration is another ownership ambiguity. Commands write stack.effect.json before entering the main pipeline. A later Blueprint, Plan, or Apply failure can therefore leave repository mutation that was never represented in the reviewed Plan or ApplyResult.

Finally, CLI pipeline tests replace Blueprint, Plan, Apply, and Finalize simultaneously. Stage suites are substantial, but there is no small contract test proving that real values cross the complete Selection -> Blueprint -> Plan -> Apply lifecycle against a temporary repository.

Why does this matter?

  • Adding a second lifecycle consumer duplicates orchestration and error policy.
  • Terminal presentation decisions determine when domain information is computed.
  • Tests verify mocked call order but cannot detect incompatible real stage outputs.
  • Configuration mutation can survive a failed scaffolding run without appearing in Plan or ApplyResult.
  • The CLI becomes the only place where the meaning of the whole lifecycle exists.

The issue is not to create a generic workflow framework. The current CLI remains the primary use case. The goal is to give that CLI one coherent application-facing lifecycle result while keeping terminal interaction as an adapter concern.

Scope

  • Shared orchestration used by interactive scaffolding and the read-only plan command.
  • Typed lifecycle results or events sufficient for terminal presentation.
  • Placement of conflict collection and other user policy relative to the lifecycle.
  • Removal of downstream dependence on raw Selection when Blueprint or later results should be authoritative.
  • Consistent propagation of planning and Finalize failures.
  • Ownership and observability of stack.effect.json mutation.
  • A real temporary-filesystem contract test crossing the principal lifecycle stages.

Acceptance criteria

  • Interactive scaffolding and the plan command share one interpretation of Blueprint, Plan, and relevant Finalize information.
  • Terminal prompts, box rendering, and streamed process output are not required to execute or test the core lifecycle orchestration.
  • Conflict decisions remain explicit CLI/user policy and do not leak backward into Plan.
  • Downstream behavior is derived from the appropriate lifecycle result rather than re-reading raw Selection intent.
  • Planning and Finalize failures are propagated consistently between interactive and read-only consumers.
  • Next steps are represented independently of terminal branches and script presence.
  • Configuration mutation is either represented by the lifecycle or has an explicit atomicity/failure contract visible to callers.
  • A contract test uses a real Catalog and temporary repository to cross Selection -> Blueprint -> Plan -> Apply.
  • The contract test covers an idempotent second run and at least one conflict-bearing path.
  • CLI-focused tests can replace the workflow interface without mocking every scaffold stage independently.

Blocked by

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    afkAutonomous slice that can be completed without human interactionenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions