Skip to content

GH-81: feat(github): export Poller.MarkProcessed for host-side cross-poller skip wiring#82

Merged
alekspetrov merged 1 commit into
mainfrom
pilot/GH-81
Jul 8, 2026
Merged

GH-81: feat(github): export Poller.MarkProcessed for host-side cross-poller skip wiring#82
alekspetrov merged 1 commit into
mainfrom
pilot/GH-81

Conversation

@alekspetrov

Copy link
Copy Markdown
Contributor

Summary

Automated PR created by Pilot for task GH-81.

Closes #81

Changes

GitHub Issue #81: feat(github): export Poller.MarkProcessed for host-side cross-poller skip wiring

Context

The github integration Poller keeps a processed-issues set (in-memory map + write-through ProcessedStore.Mark, sdk/integrations/github/poller.go:1043) so findOldestUnprocessedIssue skips already-handled issues. The exported surface currently offers ClearProcessed, IsProcessed, ProcessedCount, and Reset (poller.go:~1510-1547) — but NOT MarkProcessed. The unexported markProcessed exists and is used internally on dispatch.

Host applications need to mark issues processed from OUTSIDE the poller: when a host-side epic executor creates sub-issues and runs them sequentially itself, it must mark those issue numbers in every poller so they are not independently dispatched for parallel execution. The in-tree Pilot poller exposes exactly this as a one-line exported wrapper, and its absence in the SDK poller has caused live duplicate concurrent executions of epic children.

Change

Export MarkProcessed on *Poller in sdk/integrations/github/poller.go, placed next to ClearProcessed:

// MarkProcessed marks an issue as processed (in-memory + persistent store),
// so the poll cycle will not dispatch it. Used by hosts that create and
// execute sub-issues themselves and must prevent independent re-dispatch.
func (p *Poller) MarkProcessed(number int) {
	p.markProcessed(number)
}

Semantics identical to the internal path: in-memory map insert + write-through processedStore.Mark("github", p.repoKey(), strconv.Itoa(number)) when a store is configured. No other behavior changes.

Acceptance Criteria

  • Poller.MarkProcessed(number int) exported, delegating to the existing unexported markProcessed.
  • After MarkProcessed(n): IsProcessed(n) == true, and a poll cycle does not dispatch issue n.
  • With a configured ProcessedStore, Mark is called with the poller's own repo key (verify via a fake store in a table-driven test).
  • ClearProcessed(n) after MarkProcessed(n) restores dispatchability (round-trip test).
  • No changes to any other exported API; go test ./... green.

Out of Scope

  • Any change to ProcessedStore interface or core.PollerDeps.
  • Host-side wiring (lands in the consuming application).

Planned Steps (execute all in sequence)

  • Step 1: feat(github): export Poller.MarkProcessed for host-side cross-poller skip wiring — In sdk/integrations/github/poller.go, add an exported one-line wrapper func (p *Poller) MarkProcessed(number int) { p.markProcessed(number) } placed adjacent to ClearProcessed (~line 1510). The wrapper delegates to the existing unexported markProcessed, preserving the in-memory map insert + write-through processedStore.Mark("github", p.repoKey(), strconv.Itoa(number)) semantics with no behavior change. Add table-driven tests in sdk/integrations/github/poller_test.go (or the nearest existing processed-set test file) covering: (a) MarkProcessed(n) -> IsProcessed(n) == true; (b) with a fake ProcessedStore, Mark is invoked exactly once with source "github", the poller's own repoKey(), and strconv.Itoa(n); (c) a poll cycle after MarkProcessed(n) does not dispatch n (assert via findOldestUnprocessedIssue skipping it); (d) round-trip: ClearProcessed(n) after MarkProcessed(n) restores dispatchability. Verify no other exported API changes (re-run TestPublicAPILocked if the github package has an equivalent guard; otherwise diff exported decls manually) and confirm go test -race ./... and go vet ./... are green.

…skip wiring

Hosts that create and execute sub-issues themselves (e.g. epic executors)
need to mark issue numbers processed in every poller from outside, to
prevent independent re-dispatch and duplicate concurrent executions.
MarkProcessed delegates to the existing unexported markProcessed with no
behavior change (in-memory map insert + write-through ProcessedStore.Mark).
@alekspetrov
alekspetrov merged commit 0404049 into main Jul 8, 2026
3 checks passed
@alekspetrov
alekspetrov deleted the pilot/GH-81 branch July 8, 2026 20:21
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(github): export Poller.MarkProcessed for host-side cross-poller skip wiring

1 participant