feat(context-graph): GitHub repo one-shot ingestion skill + CLI trigger#862
feat(context-graph): GitHub repo one-shot ingestion skill + CLI trigger#862Ruchitha1608 wants to merge 2 commits into
Conversation
Adds a one-shot ingestion playbook for GitHub repositories, following the same pattern as the Linear team skill merged in potpie-ai#839. - Playbook (domain/playbooks/github_repo_one_shot_ingestion.md): phases to enumerate commits, PRs, and issues; emits Activity, Person, Fix (merged PRs only), BugPattern, and Decision nodes. Merge commits and bot authors are explicitly skipped. BugPattern keys are stable and designed to converge with the Linear sibling skill for cross-source merge. - CLI: adds `potpie pot repo ingest <owner/repo>` with owner/repo validation, mirroring `potpie pot linear-team ingest`. - Tests: 6 contract checks enforcing frontmatter, bounded list calls, Fix-from- merged-PR-only rule, and current ontology edge names.
📝 WalkthroughWalkthroughThis pull request introduces a complete one-shot GitHub repository ingestion feature, consisting of a CLI entry point, a detailed playbook specification, and comprehensive contract tests. The CLI command submits ingestion events; the playbook defines the full procedure including entity mutations and ontology rules; and the tests validate the playbook against specific behavioral contracts. ChangesGitHub Repo One-Shot Ingestion
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
potpie/context-engine/tests/unit/test_github_repo_one_shot_ingestion_skill.py (2)
20-31: 💤 Low valueConsider using a YAML parser for frontmatter.
The current frontmatter parsing splits on
:which works for simple key-value pairs but won't handle multi-line YAML values, quoted strings with colons, or other YAML features. For contract tests, this is acceptable, but usingpyyamlwould be more robust if the frontmatter format evolves.📦 Optional enhancement using PyYAML
+import yaml + def _read_skill() -> tuple[dict[str, str], str]: raw = SKILL_PATH.read_text(encoding="utf-8") assert raw.startswith("---\n") end = raw.find("\n---\n", 4) assert end > 0 - frontmatter: dict[str, str] = {} - for line in raw[4:end].splitlines(): - if ":" not in line: - continue - key, _, value = line.partition(":") - frontmatter[key.strip()] = value.strip() + frontmatter = yaml.safe_load(raw[4:end]) return frontmatter, raw[end + 5:]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@potpie/context-engine/tests/unit/test_github_repo_one_shot_ingestion_skill.py` around lines 20 - 31, Replace the ad-hoc frontmatter parsing in _read_skill with a YAML parser: read the file with SKILL_PATH.read_text, locate the frontmatter block between the leading "---" and the following "\n---\n" as you do now, then parse that frontmatter string using yaml.safe_load (from pyyaml) into the frontmatter dict instead of the manual colon-splitting loop, and return the parsed frontmatter and the body (raw[end + 5:]) as before; ensure you import yaml and handle the parsed value being None by returning an empty dict.
62-67: 💤 Low valueCase-insensitive string matching is fragile.
The test lowercases the body and checks for
"do not emit \fix` from a github issue"and"do not emit `resolved` from a github issue". This works with the current playbook (lines 290-293: "Do NOT emit \Fix`" and "Do NOT emit `RESOLVED`"), but if the playbook changes capitalization, the test might break. Consider more specific assertions.🔍 Optional: More robust assertion
- assert "do not emit `fix` from a github issue" in lowered - assert "do not emit `resolved` from a github issue" in lowered + # Check for the prohibition regardless of case/punctuation variations + import re + assert re.search(r"do\s+not\s+emit.*`fix`.*from.*github\s+issue", lowered) + assert re.search(r"do\s+not\s+emit.*`resolved`.*from.*issue", lowered)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@potpie/context-engine/tests/unit/test_github_repo_one_shot_ingestion_skill.py` around lines 62 - 67, The test test_github_repo_skill_forbids_fix_from_issues is fragile because it lowercases the whole body and asserts exact-cased substrings; instead, perform a case-insensitive match or more targeted checks on the original body returned by _read_skill(): for example, use a regex search with the IGNORECASE flag to look for the phrase "do not emit `fix` from a github issue" and similarly for "`resolved`", or assert that the sequence of tokens "do not emit", the backticked token "`fix`" (or "`resolved`"), and "github issue" appear in order — update the assertions in that test to use re.search(..., flags=re.IGNORECASE) or equivalent token-order checks against the body variable rather than lowercasing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@potpie/context-engine/tests/unit/test_github_repo_one_shot_ingestion_skill.py`:
- Around line 20-31: Replace the ad-hoc frontmatter parsing in _read_skill with
a YAML parser: read the file with SKILL_PATH.read_text, locate the frontmatter
block between the leading "---" and the following "\n---\n" as you do now, then
parse that frontmatter string using yaml.safe_load (from pyyaml) into the
frontmatter dict instead of the manual colon-splitting loop, and return the
parsed frontmatter and the body (raw[end + 5:]) as before; ensure you import
yaml and handle the parsed value being None by returning an empty dict.
- Around line 62-67: The test test_github_repo_skill_forbids_fix_from_issues is
fragile because it lowercases the whole body and asserts exact-cased substrings;
instead, perform a case-insensitive match or more targeted checks on the
original body returned by _read_skill(): for example, use a regex search with
the IGNORECASE flag to look for the phrase "do not emit `fix` from a github
issue" and similarly for "`resolved`", or assert that the sequence of tokens "do
not emit", the backticked token "`fix`" (or "`resolved`"), and "github issue"
appear in order — update the assertions in that test to use re.search(...,
flags=re.IGNORECASE) or equivalent token-order checks against the body variable
rather than lowercasing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: f810c758-107b-4c0f-a866-6144e0f327dd
📒 Files selected for processing (3)
potpie/context-engine/adapters/inbound/cli/main.pypotpie/context-engine/domain/playbooks/github_repo_one_shot_ingestion.mdpotpie/context-engine/tests/unit/test_github_repo_one_shot_ingestion_skill.py
Address CodeRabbit review: add docstrings to all test functions and helper to meet 80% coverage threshold; replace fragile lowercased string checks with re.search(IGNORECASE) in test_github_repo_skill_forbids_fix_from_issues.
Summary
domain/playbooks/github_repo_one_shot_ingestion.md— a one-shot ingestion playbook for GitHub repositories, direct sibling to the Linear team skill merged in feat(context-graph): one-shot Linear team ingestion skill + CLI trigger #839. Same 3-phase structure (enumerate → drain batches → finalize), same ontology, adapted for commits, PRs, and issues.potpie pot repo ingest <owner/repo>CLI command — mirrorspotpie pot linear-team ingest, submits a(github, github_repo, one_shot_ingest)event to the reconciliation pipeline.Key design decisions
Fix from merged PRs only — unlike the Linear skill (which never emits
Fix), this skill emitsFixentities from merged PRs when they link or label a bug. Issues never emitFix, matching Linear's rule.Cross-source BugPattern convergence —
BugPatternkeys (bug_pattern:github-<repo-slug>:<symptom-slug>) are stable and designed to match keys written by the Linear sibling skill for the same symptom, so nodes from both sources merge in the graph without manual linking.Merge commit and bot author filtering — merge commits (
Merge pull request #...,Merge branch '...') and bot authors (logins ending in[bot]) are explicitly skipped to avoid noise in the Activity and Person graphs.Test plan
pytest tests/unit/test_github_repo_one_shot_ingestion_skill.py)pytest tests/unit/test_linear_team_one_shot_ingestion_skill.py)potpie pot repo ingestrenders inpotpie pot repo --help/, empty owner, empty repo) exits with error