Skip to content

feat(bg): B-0442.2 — merged-PR fetch via gh CLI (10 tests pass)#3014

Merged
AceHack merged 2 commits into
mainfrom
otto-b0442-2-merged-pr-fetch-slice-2-impl-2026-05-13
May 13, 2026
Merged

feat(bg): B-0442.2 — merged-PR fetch via gh CLI (10 tests pass)#3014
AceHack merged 2 commits into
mainfrom
otto-b0442-2-merged-pr-fetch-slice-2-impl-2026-05-13

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented May 13, 2026

Summary

Slice 2 of B-0442. The missed-substrate cascade detector now fetches recent merged PRs via `gh pr list --state merged --search "merged:>{iso}"` and reports the candidate set within a configurable lookback window (default 30min).

What lands

  • spawnSync + sonarjs lint suppression with rationale
  • Adapter pattern for deterministic tests
  • gh JSON output type-guarded
  • New `--lookback-min` flag (default 30)
  • `cascadesDetected` still 0 in slice 2 — slice 3 will fetch branch HEADs + compare against squash content

Tests

```
bun test
10 pass
0 fail
20 expect() calls
```

Three-service mechanization status

Service Skeleton Real detection
B-0440 standing-by #3006 #3011 (commit-history poll)
B-0441 backlog-ready #3007 #3012 (backlog row scan)
B-0442 missed-substrate #3008 THIS PR (merged-PR fetch)

🤖 Generated with Claude Code

…tion)

Slice 2 of B-0442. The missed-substrate cascade detector now fetches
recent merged PRs via `gh pr list --state merged --search "merged:>{iso}"`
and reports the candidate set within a configurable lookback window
(default 30min).

Key design choices:
- spawnSync (execFile-style, no shell) + sonarjs lint suppression
  with rationale (matches B-0440.2 pattern)
- Adapter pattern (now + fetchRecentMergedPRs) for deterministic tests
- gh JSON output parsed with type-guard filter to reject malformed
  entries
- New --lookback-min flag (default 30min)
- cascadesDetected stays 0 in slice 2 — slice 3 will fetch each
  branch's HEAD and compare against the squash content to surface
  actual cascades

Test results: 10 pass / 0 fail / 20 expect() calls (slice 1 had 13/21).

Future slices:
- Slice 3: per-merged-PR branch-HEAD fetch + squash content compare
  (detects actual drift)
- Slice 4: cascade-detection payload + bus publish (requires B-0400
  schema extension for missed-substrate-cascade topic)
- Slice 5: optional auto-recovery-PR opening (gated)
- Slice 6: cron registration + integration tests

Composes with:
- B-0442 + B-0442.1 (PR #3008 — skeleton this extends)
- B-0440.2 + B-0441.2 (PR #3011 + #3012 — companion services with
  real detection)
- B-0400 (bus protocol — slice 4)
- PR #2997 (the Otto-section-missed-PR-2980-by-3min recovery — the
  canonical operational example this service mechanizes)

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 13, 2026 18:26
@AceHack AceHack enabled auto-merge (squash) May 13, 2026 18:26
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6229a2c836

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/bg/missed-substrate-detector.ts Outdated
Comment thread tools/bg/missed-substrate-detector.ts Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR advances the B-0442 missed-substrate detector from a slice-1 skeleton to slice 2 by adding a gh pr list --state merged-based fetch of recently merged PRs and reporting the size of the candidate window via the detector’s JSON output.

Changes:

  • Add gh CLI integration (via spawnSync) to fetch merged PRs within a configurable lookback window.
  • Extend config/CLI parsing with --lookback-min (default 30) and include candidatesScanned in the poll result.
  • Update tests to use injected adapters for deterministic pollOnce behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
tools/bg/missed-substrate-detector.ts Implements merged-PR fetching via gh, adds lookback config/flag, and expands poll result shape.
tools/bg/missed-substrate-detector.test.ts Updates tests for slice 2, exercising adapter-injected pollOnce and new CLI flag parsing.
Comments suppressed due to low confidence (2)

tools/bg/missed-substrate-detector.ts:75

  • The gh call drops stderr and on any failure (non-zero exit, missing stdout, JSON parse/type-guard failure) returns an empty list. That makes pollOnce report "no merged PRs" even when gh is missing/auth-failed/output-changed. Please surface fetch failures distinctly (e.g., return an error from the adapter and reflect it in note, and/or capture stderr) so operational issues aren’t misreported as an empty candidate set.
      { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] },
    );
    if (result.status !== 0 || !result.stdout) return [];
    try {

tools/bg/missed-substrate-detector.ts:110

  • note treats merged.length === 0 as "no merged PRs", but merged can also be empty due to gh failures/parse errors. Once fetch failures are surfaced, consider distinguishing these cases in the note so the JSON output is diagnostic in cron/daemon logs.
    note: merged.length === 0
      ? `no merged PRs in last ${config.lookbackMin}min lookback window`
      : `${merged.length} merged PR(s) in last ${config.lookbackMin}min; slice 3 will compare each branch HEAD against squash content`,
  };

Comment thread tools/bg/missed-substrate-detector.ts Outdated
Comment thread tools/bg/missed-substrate-detector.ts
…ion, fetchLimit configurable, header accuracy)

1. P1: gh-failure no longer silently treated as zero merged PRs.
   FetchResult is now a discriminated union of {status: "ok", prs,
   truncated} | {status: "gh-error", reason}. PollResult.fetchStatus
   surfaces the distinction in the note.

2. P2: Hard-coded 50-item cap replaced with configurable fetchLimit
   (default 100, settable via --fetch-limit). When results hit the
   cap, fetchTruncated:true is set + warning included in note so
   caller can raise --fetch-limit or shorten --lookback-min.

3. Header comment corrected: removed inaccurate claim that the
   slice checks branch-exists-in-remote-tracking-refs. Slice 2 only
   fetches merged-PR metadata; the actual branch HEAD comparison
   lands in slice 3.

4. Duplicate of #2 (same 50-cap concern from a second reviewer
   perspective) resolved by the same fix.

New tests:
- gh-error path surfaces fetchStatus + reason in note
- truncation path sets fetchTruncated + warning in note
- --fetch-limit positive-integer validation (rejects non-integer)

Test results: 13 pass / 0 fail / 34 expect() calls (was 10 / 20).

Co-Authored-By: Claude <noreply@anthropic.com>
@AceHack AceHack merged commit 74df41f into main May 13, 2026
25 checks passed
@AceHack AceHack deleted the otto-b0442-2-merged-pr-fetch-slice-2-impl-2026-05-13 branch May 13, 2026 18:34
AceHack added a commit that referenced this pull request May 13, 2026
…not real cascade detection) (#3023)

Slice 4 of B-0442. Wires the bus-publish path for the missed-substrate
cascade detector. Slice 3 (branch-HEAD vs squash-content compare)
is NOT yet implemented; the detectCascade adapter is a stub that
always returns null.

SUBSTRATE-HONEST FRAMING (per Riven's P0 catch on the analogous
B-0440 cascade — envelope 6c689634-...):

This PR ships:
- Bus-publish path (try/catch wrapped, structured publish-error
  surfacing, missed-substrate-cascade topic from B-0400)
- Adapter abstraction (detectCascade injectable for tests; real
  slice-3 comparator plugs in later)
- CascadeFinding payload schema (prNumber, branchName,
  missingCommits, urgency)
- CLI flags (--no-publish, --agent, --to, --fetch-limit)

This PR does NOT ship:
- Real branch-vs-squash comparator (slice 3)
- Auto-recovery-PR opening (slice 5)
- Cron registration (slice 6)

In production right now, this service WILL fetch merged PRs but
WILL NOT detect any cascades (stub returns null). The reactive
loop is wired but inert until slice 3 lands.

Riven's P0 warning preserved: do NOT frame this as "missed-
substrate cascade detection is operational." The framing is "bus-
publish wiring complete; slice-3 detector stub awaiting real
compare logic."

Key design choices:
- Adapter pattern (now / fetchRecentMergedPRs / detectCascade /
  publishCascade) for full test injectability
- spawnSync (execFile-style) for gh CLI invocation
- Canonical SENDER_IDS / AGENT_IDS reuse (Riven/Vera/Copilot
  cross-PR finding)
- try/catch on publishCascade (daemon survives bus IO failures)

Tests: 11 pass / 0 fail / 42 expect() calls.

Composes with:
- B-0442.2 (PR #3014 — merged-PR fetch this extends)
- B-0440.4 (PR #3017 — same bus-publish pattern; first reactive
  loop closed)
- B-0441.4 (PR #3020 — proactive companion; same try/catch pattern)
- B-0400 schema extension (PR #3016 — missed-substrate-cascade topic)
- Riven adversarial review (envelopes 6c689634 + e8174b34)

Co-authored-by: Claude <noreply@anthropic.com>
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.

2 participants