Skip to content

GitHub fetch handler: support targeted fetch by issue_number / pull_number #279

@chubes4

Description

@chubes4

Problem

DataMachineCode\Handlers\GitHub\GitHub::fetchIssuesOrPulls() only supports list-style filtering (state, labels, search, exclude_keywords, timeframe_limit, timeframe). There is no way to configure the fetch handler to return one specific issue or pull request by number.

This blocks any flow that needs to run an imported agent against a single, externally-supplied issue — for example the upcoming wc-static-site-agent CI workflow on chubes4/wp-site-generator#99, where workflow_dispatch supplies an issue_number and the imported flow should hydrate that exact issue as its source of truth.

The only workarounds today are:

  1. Inject the issue body into the AI prompt and let the fetch step return whatever the label query produces — creates two competing truths (fetch packet vs. prompt) and breaks the flow contract.
  2. Abuse search with the issue title — brittle (collisions, label drift, client-side keyword match, not GitHub search).
  3. Bypass the fetch step entirely from a probe by calling GitHubAbilities::getIssue() directly — moves fetch logic into the consumer and breaks the bundle's flow contract.

All three are paper-overs. The next consumer (Intelligence flows, Extra Chill event triage, any single-item targeted run) will hit the same gap.

Proposed shape

Add optional issue_number and pull_number fields to the GitHub fetch handler config. When either is set on a flow's handler_config.github:

  • The handler bypasses GitHubAbilities::listIssues() / listPulls() and calls the existing GitHubAbilities::getIssue() (line 1178) / getPullRequest() instead.
  • The single returned item is normalized into the same DataPacket shape as the existing list path (title, content, metadata.github_* fields, dedup_key of `github_<data_source>`).
  • List-narrowing config (search, exclude_keywords, timeframe_limit, timeframe, labels) is ignored in targeted mode (they cannot narrow further than one item) — log an info line if any are set alongside a number.
  • `max_items` is implicitly 1.
  • Existing `processed_items` dedupe still applies so reruns are idempotent (consumers can opt out by clearing the row, same as today).
  • If the fetched issue/PR doesn't match the configured `state` (e.g. `open`), drop it with an info log so closed/locked items don't silently flow through.

When neither number is set, behavior is unchanged.

Settings UI

Add the two number fields to `GitHubSettings` with help text that they take precedence over list-narrowing fields.

Validation

  • `issue_number` and `pull_number` are mutually exclusive — error if both set.
  • `data_source` must align: `issue_number` requires `issues`; `pull_number` requires `pulls`.

Tests

Smoke test (no network) that:

  • Configuring `issue_number = N` calls `getIssue` instead of `listIssues`.
  • Configuring `pull_number = N` calls `getPullRequest` instead of `listPulls`.
  • Mismatched `data_source` returns a clear error.
  • Both numbers set returns a clear error.
  • DataPacket shape matches the existing list-path shape for a single item.

Why upstream

Per the wc-site-generator/intelligence-chubes4 site rule: fix upstream first, never paper over. This gap will be hit again by any consumer that wants targeted single-item runs (CI dispatch, webhook responder, retry-by-number, scheduled per-item flows). Solving it once in DMC keeps every consumer simple.

Downstream consumer

chubes4/wp-site-generator#99 (Phase 1 CI workflow for wc-static-site-agent) is paused on this. Once this lands, that probe just sets `handler_config.github.issue_number = $issue_number` and runs the imported flow unchanged — no shim, no prompt injection.

AI assistance

  • AI assistance: Yes
  • Tool(s): Claude Code (Sonnet 4.5)
  • Used for: Drafting this issue from the gap analysis on the wc-site-generator side.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions