Skip to content

feat: add --issue flag to factory ceo/run for direct issue targeting#210

Closed
akashgit wants to merge 3 commits into
mainfrom
experiment/54-issue-flag
Closed

feat: add --issue flag to factory ceo/run for direct issue targeting#210
akashgit wants to merge 3 commits into
mainfrom
experiment/54-issue-flag

Conversation

@akashgit
Copy link
Copy Markdown
Owner

Summary

  • New factory/issue.py module with IssueSpec dataclass, URL/ref parsing, remote inference, and issue fetching via gh/glab CLI
  • --issue flag added to both ceo and run subparsers with mutual exclusion against --prompt, --focus, --no-github, --mode interactive, and --mode research
  • Issue content fetched, formatted as markdown, persisted to .factory/strategy/current.md, and passed through _build_ceo_task with directive and finalize tracking sections
  • 25 new tests covering parsing (GitHub/GitLab URLs, bare numbers, shorthand), remote inference (HTTPS/SSH), formatting, subprocess mocking, error handling, and CLI mutual-exclusion validation

Closes #209

Test plan

  • pytest tests/test_issue.py -v — 25 tests pass
  • pytest -v — full suite (355 tests) passes
  • ruff check . — clean
  • mypy factory/issue.py factory/cli.py — clean

🤖 Generated with Claude Code

Adds the ability to point the factory at a GitHub or GitLab issue
directly, fetching the issue content and using it as the build spec.

- New module factory/issue.py with IssueSpec dataclass, parse_issue_ref,
  infer_remote, fetch_issue, and format_issue_as_spec
- --issue flag on both ceo and run subparsers
- Mutual exclusion with --prompt, --focus, --no-github, --mode interactive/research
- Issue spec persisted to .factory/strategy/current.md (same as --prompt)
- Issue number/URL passed through to _build_ceo_task for CEO directive
- 25 tests covering parsing, remote inference, formatting, fetching, and CLI validation

Closes #209

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

❌ Patch coverage is 84.51613% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.94%. Comparing base (7521938) to head (d7e81ea).

Files with missing lines Patch % Lines
factory/cli.py 65.15% 23 Missing ⚠️
factory/issue.py 98.87% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #210      +/-   ##
==========================================
- Coverage   87.01%   86.94%   -0.07%     
==========================================
  Files          51       52       +1     
  Lines        7300     7447     +147     
==========================================
+ Hits         6352     6475     +123     
- Misses        948      972      +24     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

akashgit and others added 2 commits May 10, 2026 00:32
Fixes ordering bug in cmd_run where --issue validation happened after
the network call to fetch the issue. Also moves --no-github check in
cmd_ceo to early validation block. Adds missing cmd_run mutual exclusion
tests (4 new tests).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@akashgit
Copy link
Copy Markdown
Owner Author

✅ Factory Review: KEEP

Verdict: KEEP
Reason: Issue #202 implemented: --issue flag for factory ceo/run. 29 tests, clean lint/types, real integration test with issue #202 verified.

Experiment: #54
Hypothesis: Add --issue flag to factory ceo and factory run for GitHub/GitLab issue targeting (issue #202)

Score Comparison

Metric Value
Before 0.7703
After 0.8909
Delta +0.1206
Threshold 0.8000

Guard Checks

Check Result
scope ✅ PASS
eval_immutable ✅ PASS
smoke_test ✅ PASS
anti_pattern ✅ PASS

Real Integration Test

Reviewer Notes

  • Reviewer flagged 3 issues (ordering bug in cmd_run, --no-github ordering in cmd_ceo, missing cmd_run tests) — all fixed in commit 50bd4f4
  • ghelleks (issue creator) invited as collaborator for review

Posted by Factory CEO — PR left open for human review

Copy link
Copy Markdown
Owner Author

@akashgit akashgit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #210 Review: feat: add --issue flag to factory ceo/run for direct issue targeting

+561 / -8 across 3 files — new factory/issue.py module, CLI integration in factory/cli.py, and 25 tests in tests/test_issue.py.


Overview

Adds --issue to factory ceo and factory run, allowing users to point the factory at a GitHub/GitLab issue by number, URL, or shorthand (owner/repo#N). The issue is fetched via gh/glab CLI, formatted as a markdown spec, persisted to .factory/strategy/current.md, and injected into the CEO task with a directive and finalize-tracking section.

Well-structured feature. The parsing is solid, forge detection is smart, and the test coverage is thorough. A few things to fix:


Issues

1. Missing --issue + --mode research mutual exclusion in cmd_run (bug)

cmd_ceo blocks this combination (line 1377), but cmd_run does not. The run subparser accepts --mode research, so a user can run factory run /path --issue 42 --mode research and bypass the guard. The test suite (TestCLIMutualExclusion) also doesn't cover this case for run.

factory/cli.py:2199 — add after the no_github check:

if issue_ref and mode == "research":
    print("Error: --mode research and --issue are mutually exclusive. ...")
    return 1

But note: mode isn't parsed until line 2215, after the issue fetch at line 2205. So either move the mode parsing up, or place this check after line 2221. Placing it after means the issue would already be fetched before the error fires — wasteful but not broken. Alternatively, move the mode extraction before the fetch block.

2. Duplicated issue-handling code between cmd_ceo and cmd_run (quality)

The following block appears nearly identically in both functions:

  • Three mutual exclusion checks (--prompt, --focus, --no-github)
  • fetch_issue + format_issue_as_spec call
  • strategy_dir creation and current.md write
  • issue_number / issue_url extraction

Extract this into a helper like _resolve_issue(issue_ref, project_path) -> tuple[str, int, str] that returns (context, number, url), and a _check_issue_exclusions(issue_ref, prompt_file, focus, no_github) or similar. This keeps both command paths in sync and avoids the already-demonstrated gap (the missing research check in cmd_run).

3. issue_number=issue_number, issue_url=issue_url crammed on one line

factory/cli.py:1472 — the surrounding kwargs are one-per-line. This breaks the pattern:

        interactive_idea=interactive_idea,
        research_ideation=research_ideation,
        messages=pending,
        issue_number=issue_number, issue_url=issue_url,  # ← two on one line

Minor Notes

  • Nested GitLab groups: parse_issue_ref captures owner/repo with [^/]+/[^/]+, which won't handle group/subgroup/project. Edge case, not blocking.
  • --issue + --loop: No guard against this. In the heartbeat loop, every cycle gets the same issue spec. Probably fine for multi-part issues, but the behavior could surprise users. Consider at least a log warning.
  • Loop re-detection at line 2292 uses bool(prompt_file or context) without issue_ref — works because context was set from the issue, but fragile if future changes clear context. Consider adding issue_ref for consistency.

What's Good

  • issue.py is clean, well-separated, and easy to test independently
  • Forge auto-detection from git remote (SSH + HTTPS) is thorough
  • Error messages are clear and actionable ("CLI not found", "Cannot parse issue reference")
  • The ## Issue Tracking section in the CEO task wiring the --issue flag to factory finalize is a nice end-to-end touch
  • Test coverage is excellent — 25 tests covering parsing, remote inference, formatting, subprocess mocking, error handling, and CLI mutual exclusion

Verdict

Fix issue #1 (the missing research mutual exclusion in cmd_run) before merge. Issue #2 (duplication) is the right follow-up — the gap in #1 is a direct consequence of the duplication, so extracting the shared logic prevents this class of bug.

@akashgit
Copy link
Copy Markdown
Owner Author

Addendum: Consider expanding --focus instead of adding --issue

On reflection, there's a design-level concern worth raising.

--focus already means "build exactly this one thing and exit." An issue reference is just another way to specify what that one thing is. Instead of a new --issue flag with its own set of mutual exclusion rules, --focus could be expanded to detect issue refs:

# Today (backlog item by name)
factory ceo /path --focus "dashboard UI"

# Proposed (issue refs detected automatically)
factory ceo /path --focus 42
factory ceo /path --focus "https://github.com/owner/repo/issues/42"
factory ceo /path --focus "owner/repo#42"

The issue.py module (parsing, fetching, formatting) would still be needed — but the CLI integration would collapse dramatically:

The detection logic in --focus would be straightforward: if the value matches parse_issue_ref (bare number, URL, or owner/repo#N), fetch the issue; otherwise treat it as a backlog item name (existing behavior).

One consideration: --focus currently restricts to improve/research mode, while --issue works with auto mode detection. When the focus value is an issue ref (providing a full spec), that mode restriction could be relaxed — or auto-detection could handle it naturally since the spec provides has_prompt=True context.

This would make the PR significantly simpler: issue.py + a small change to how --focus resolves its value, rather than threading a new flag through the entire CLI plumbing.

@akashgit
Copy link
Copy Markdown
Owner Author

Closing in favor of a reworked PR that expands --focus instead of adding --issue. See #211 for the design rationale.

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: add --issue flag to factory ceo/run for direct issue targeting

1 participant