Repo: motir-core. Surfaced by motir run MOTIR-2903 under run.md guard #4 (the "X doesn't exist" claim gate). MOTIR-2903's recommended mechanism reads "a merged PR's diff touches every path its acceptance criteria name" and adds "the channel already computes description↔graph references; this is the same read against the PR set." It is not the same read: the PR set carries no diff. This card supplies the substrate; MOTIR-2903 then builds the advisory on it.
origin/main @ 64fb9e6e)prisma/schema.prisma — GithubPullRequest carries provider · repoId · number · state · merged · headRef · title · workItemId · linkedManually · createdAt · updatedAt. No path column, and no merge INSTANT (merged is a boolean; updatedAt moves on any later delivery, so it cannot answer "did this land after that card was filed?"). A scan of all 82 models finds no table holding a pull request's files. The one model in the schema that stores repository paths is DesignAsset.sourcePath, and those paths are pushed by CI through POST /api/work-items/[id]/design-evidence — never read back from a pull request.lib/repositories/githubPullRequestRepository.ts — nine methods (findByRepoAndNumber, lockByRepoAndNumber, findByRepoAndHeadRef, countOtherOpenByWorkItem, listByWorkItemWithContext, findByIdWithInstallation, searchCandidates, setWorkItemLink, upsert). None returns a path.lib/github/ — twenty read leaves, none of which calls GET /repos/{owner}/{repo}/pulls/{n}/files. historicalPullRequests.ts is the closest shape and the model to copy: an installation-authenticated, paginated, rate-limit-aware REST read that normalizes PR metadata only.The obvious cheaper answer is to compare the subsumed card's prose against the COVERING card's prose and never call GitHub at all. That answer is dead on the canonical fixture, and the measurement is short enough to repeat:
workflowsService, getWorkflow, listStatusesByProject, getStatusByKey, or lib/services/workflowsService.ts. Its parent story MOTIR-2796 contains none either, and none of 2796's twenty-one children names a workflow read.c99efdc7 (PR #2059, 2026-08-15) touches lib/services/workflowsService.ts, three days after MOTIR-2757 was filed and two days before a run claimed it.GithubPullRequest.mergedAt DateTime? — stamped from the webhook payload's pull_request.merged_at on the delivery that reports the merge, left null otherwise. This is the ordering fact a subsumption check needs; updatedAt cannot serve, because a later check_suite-driven upsert moves it.GithubPullRequest.changedPaths String[] — the repo-relative paths the merge touched, capped (a MAX_CAPTURED_PR_PATHS constant; a PR past the cap stores the first N and sets a changedPathsTruncated Boolean, so a consumer can never read a partial set as a complete one — the no-silent-caps rule). A column on the existing row rather than a child table, deliberately: the shipped github_pull_request RLS policy then covers it unchanged, and no consumer wants a path without its PR.lib/github/pullRequestFiles.ts — a new read leaf on historicalPullRequests.ts's exact shape: installation-authenticated, per_page=100, bounded page walk, rate-limit backoff, a typed error class, and a page cap that REPORTS truncation rather than stopping quietly.githubWebhookService's pull_request handler, on the transition into merged. Best-effort and post-commit, on enqueueCodeGraphIndex's precedent (lib/github/indexEnqueue.ts): the status sync is the load-bearing effect of that delivery and a GitHub blip must never fail or roll it back. A failed capture is swallowed, logged, and leaves changedPaths empty.findMergedTouchingPaths(workspaceId, paths, since, excludeWorkItemId, tx) (name it as you like), one query, returning the merged rows whose changedPaths intersect paths and whose mergedAt is after since. This is the single read MOTIR-2903 consumes, and it belongs here so that card adds no data access of its own.pull_request delivery reporting a merge stores that PR's changed paths and its merge instant on the github_pull_request row; a delivery for an OPEN pull request stores neither. Both directions asserted against a real Postgres row, not against the fetcher's return value.undici MockAgent convention the sibling GitHub suites use) and asserted to request /repos/{owner}/{repo}/pulls/{number}/files with the installation token — never the app JWT.changedPaths empty. Assert the transition the sync performed, not merely that no exception escaped — a swallowed error that also swallowed the sync is the failure mode.MAX_CAPTURED_PR_PATHS stores exactly that many paths and sets the truncation flag; a pull request under the cap stores every path and leaves the flag false.changedPaths contains a queried path and whose mergedAt is later than the since argument, and omits: a row merged before since, a row whose paths do not intersect, an OPEN row, and the row linked to excludeWorkItemId. One case per omission, so a single over-broad WHERE cannot pass them all.prisma migrate diff --from-schema … --to-config-datasource --exit-code reports no drift after the migration — the build job's own gate, run locally before the pull request opens.changedPaths defaults to empty and mergedAt to null, and no shipped consumer of GithubPullRequest changes behaviour. Assert the Development-surface DTO's shape is unchanged.scripts/'s existing pattern, and its own card.historicalPullRequests.ts records why a GitHub-specific read leaf sits beside the GitProvider seam rather than inside it; the same reasoning holds here.prisma/schema.prisma — the GithubPullRequest model (~L4262) and its @@unique([repoId, number]).lib/github/historicalPullRequests.ts — the read leaf to mirror: pagination, retryDelayMs, MAX_PULL_REQUEST_PAGES, the typed error, and the header explaining why it is a leaf and not a seam method.lib/github/indexEnqueue.ts — the best-effort, post-commit side-effect precedent, and its PROD-443 reasoning for why a transport call must not be able to fail a committed mutation.lib/services/githubWebhookService.ts — the pull_request handler and changeRequestStatusSync, the effect that must stay unaffected.lib/repositories/githubPullRequestRepository.ts — where the accessor lands, and the countOtherOpenByWorkItem shape to follow.