Skip to content

feat(brainstormer): forge-loop brainstorm CLI (dry-run + --apply) (#124)#145

Merged
hadamrd merged 1 commit into
trunkfrom
loop/124-feat-brainstormer-forge-loop-brainstorm
May 28, 2026
Merged

feat(brainstormer): forge-loop brainstorm CLI (dry-run + --apply) (#124)#145
hadamrd merged 1 commit into
trunkfrom
loop/124-feat-brainstormer-forge-loop-brainstorm

Conversation

@hadamrd
Copy link
Copy Markdown
Owner

@hadamrd hadamrd commented May 28, 2026

Closes #124.

Summary

New forge-loop brainstorm subcommand that wires the existing Brainstormer (#122) and GhClient (#83/#123) into an operator-facing CLI. Dry-run by default; --apply files epics + tickets.

Acceptance criteria coverage

Criterion Where it's tested
Default prints BrainstormReport as YAML, no GitHub calls test_brainstorm_dry_run_prints_yaml
--apply files epics first, threads Parent: #<n> into tickets test_brainstorm_apply_files_epics_first
Epic labels axis:<name> + epic test_brainstorm_apply_labels_epic
Ticket labels axis:<name> + loop:ready test_brainstorm_apply_labels_ticket
Missing ProductVision → exit 2 test_brainstorm_missing_vision_exits_2
Invalid ProductVision (empty axes) → exit 2 test_brainstorm_invalid_vision_exits_2
Partial failure → exit 1, per-title stdout/stderr reporting test_brainstorm_partial_failure_exits_1
Empty report → exit 0, zero create_issue calls test_brainstorm_apply_no_proposals
--apply is opt-in, never default test_brainstorm_default_never_writes (adversarial)
Registered in existing Typer app test_cli.py help-list smoke test now includes brainstorm

Supporting change

gh_client.py gains create_issue on the GhClient Protocol, GithubkitClient, and MockGhClient. The brainstorm CLI is the first writer call site, so the method ships alongside. MockGhClient gets create_issue_responses / next_issue_number / raise_on_create_titles knobs so tests can pre-stage epic numbers and inject per-title failures.

Test plan

  • pytest tests/test_cli_brainstorm.py — 9 passed
  • pytest tests/test_cli.py tests/test_brainstormer.py tests/test_gh_client.py — 59 passed

🤖 Generated with Claude Code

New `forge-loop brainstorm` subcommand wires the existing Brainstormer
(issue #122) and GhClient (issue #83/#123) into an operator-facing CLI.

Behavior:
* No flags → discover ProductVision, run Brainstormer, dump the
  BrainstormReport as YAML to stdout. Zero GitHub calls.
* --apply → file proposed epics first (labels: axis:<name> + epic),
  then file proposed tickets (labels: axis:<name> + loop:ready) with
  `Parent: #<epic-number>` cross-link bodies threading the returned
  epic numbers.
* Missing/invalid ProductVision → exit 2 with a clear stderr line and
  no partial state.
* Partial failure during --apply → exit 1; successful issues are
  reported on stdout (with their numbers), failures with title +
  error are reported on stderr.
* --apply is opt-in; default never writes.

Why opt-in matters: without a hard default-dry-run, a stray
`forge-loop brainstorm` would file epics + tickets against whatever
repo `LOOP_GH_REPO` points at — which is exactly the failure mode
the spec is defending against.

Supporting change to gh_client (#83 framework): adds `create_issue`
to the GhClient Protocol + GithubkitClient + MockGhClient. The
protocol previously covered only reads + label edits; the brainstorm
CLI is the first writer call site, so the method ships alongside.
MockGhClient gets `create_issue_responses` / `next_issue_number` /
`raise_on_create_titles` knobs so tests can pre-stage epic numbers
and inject per-title failure.

Tests (tests/test_cli_brainstorm.py): full acceptance matrix from
the issue — dry-run YAML shape, epics-filed-first ordering with
parent cross-link, epic+ticket label contracts, missing/invalid
vision exits, partial-failure exit-1 with per-title reporting,
empty-report no-op, and an adversarial "default never writes" test
that catches a future regression flipping --apply on by default.

Also registers `brainstorm` in the existing test_cli.py help-list
smoke test so future help-regressions surface early.
@hadamrd hadamrd merged commit 51670e5 into trunk May 28, 2026
2 checks passed
@hadamrd
Copy link
Copy Markdown
Owner Author

hadamrd commented May 28, 2026

Source issue #124 was closed mid-flight (state: closed). Loop refusing auto-merge. Reopen the issue OR merge manually.

@hadamrd hadamrd deleted the loop/124-feat-brainstormer-forge-loop-brainstorm branch May 28, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(brainstormer): forge-loop brainstorm CLI (dry-run + --apply)

1 participant