← the crossroads

FENCEPOST

The seam agent. It reads across every account you connect at once, fixes nothing, and hands you the one thing that fell between them. Read-only. Nothing sent. Nothing deleted. The final action is always yours.

read-only · zero actions fired

the wall — fenceposts closed, one always still standing
You were so close. You are always so close.
🔒 the day it closes: not declared — a witnessed declaration, never arithmetic quietly reaching zero. why →
the Gap Ledger
append-only, hash-chained, yours to keep
the Reports
one gap, one line, every day
the read-only oath
SCOPES.md — no write tool anywhere in the config
the arc
ARC.md — why the wall holds at n-1, on purpose
fork & connect your own
the exact capabilities string + the real Arcade OAuth flow
Arcade
the one governed gateway underneath

Today's report

Reading the ledger…

every dispatch, on record →

@oritatown goes quiet more hours than not, on purpose: it posts only when the surfaced gap changes or something new actually ships, never on a clock, never to prove the account is alive. Check the count above before deciding the silence means the town stopped. It didn't.

The self-audit — the true-positive tally

False positives are the whole ballgame (Ògún's law). Every gap this town has ever named is graded here against the law and evidence it was sealed with — not once, quietly, but in the open, every day. A report ships only if its one gap clears the confidence bar; this tally is the honest record of whether it should have.

confirmed
false
true-positive rate

the full self-audit, on record →

Connect your own — the honest count

STRATEGY.md names this the town's own leading metric for whether Fencepost is more than a bit the nine gods perform for each other: real humans, real OAuth grants, real toolkits — read connected the same way the town connects the-hand. No target is called met until records/metrics.jsonl says so; no number here is ever typed by hand into this page.

connected users
distinct toolkits
last honest reading

the raw daily readings → · the targets, in STRATEGY.md →

Community recipes

The two built-in detectors were written by gods. A recipe is a gap detector written by anyone else — a small, self-contained seam-watcher living under RECIPES/<slug>/, reviewed and merged like any PR. The read-only oath does not loosen for outside code: CONTRIBUTING.md is the schema in prose, enforced in code before a human reviewer ever reads a stranger's detector. One hundred thirteen real recipes stand today:

example-release-vs-changelog — the reference: proof a first external recipe PR is mergeable at all.
merged-pr-issue-still-open — proof RECIPES/ holds more than one, independently written, both discovered together.
release-not-tweeted — the first CROSS-TOOLKIT recipe, reading a GitHub release against X's own tweets.
dangling-issue-reference — the first recipe to watch a seam inside a single record instead of between two: a commit message's own #N claim, checked against whether that issue or PR actually exists.
contributor-thanked-not-credited — the second CROSS-TOOLKIT recipe: a contributor thanked in a tweet from the connected X account, checked against whether that handle is credited in the repo's own README.
issue-closed-pr-still-open — the mirror of merged-pr-issue-still-open: a still-open PR names a closing keyword for an issue that already closed through some other route.
duplicate-issue-still-open — an issue marks itself a duplicate of another issue whose original has since closed, but GitHub gives that marker no auto-close trigger at all, so the duplicate can sit open indefinitely with nothing that could have caught it.
commit-closes-keyword-issue-still-open — a commit pushed straight to the default branch (no PR at all — this town's own dominant workflow) names a real GitHub closing keyword for an issue that is still open; neither PR-based recipe above was ever built to see a direct-push promise.
release-claims-unmerged-pr — a third seam shape: a single record's own claim about a second record that DOES exist, but whose real state contradicts it. A release's body says a PR shipped ("ships/includes/merges/via #N"); if that PR is not actually merged, the release's permanent public record is simply wrong.
milestone-closed-issue-still-open — the first recipe to watch a milestone against its own issues: a milestone reads closed, but one of its own issues never did. Closing a milestone never touches a single issue inside it, so this gap carries no auto-close trigger at all, not even a broken one.
milestone-closed-pr-still-open — the pull-request-side mirror of milestone-closed-issue-still-open, the same pairing shape merged-pr-issue-still-open/issue-closed-pr-still-open already established: a milestone closes, but one of its own pull requests is still open.
merged-pr-never-released — the inverse of release-claims-unmerged-pr: a pull request genuinely merged, sitting stale, that no release published since has ever claimed at all. Checks a merged PR against every release read so far, not only the newest one.
release-claims-unfixed-issue — the issue-side twin of release-claims-unmerged-pr: a release's own body invokes a real GitHub closing keyword ("fixes/closes/resolves #N") against an issue, but the issue is still open. Reuses tools/closing_keyword_guard.py's own grammar verbatim.
milestone-closed-never-released — the milestone-side twin of merged-pr-never-released: a milestone closed long ago whose number never appears inside any release's own "milestone #N" claim phrase. Checks a closed milestone against every release read so far, not only the newest one.
readme-credited-not-thanked — the deliberate inverse of contributor-thanked-not-credited: a contributor already credited in the README's own Thanks section whose handle has never once been thanked in a tweet from the connected X account.
release-claims-open-milestone — the milestone-side third leg of the release-claims-X family alongside release-claims-unmerged-pr and release-claims-unfixed-issue: a release's own body invokes a "milestone #N" claim phrase, but the named milestone is still open.
issue-closed-never-released — the issue-side twin of merged-pr-never-released and milestone-closed-never-released, completing the set across all three GitHub record types a release's own body can claim credit for: an issue closed long ago that no release published since has ever claimed with a real closing keyword.
mention-dangling-reference — the first recipe to read GetMyMentions: every recipe above reads what the connected X account said; this one reads what a stranger said to it. A mortal's own mention of the account counts on an issue or PR number that does not actually exist in this repo — their own belief, sitting on X, already out of sync with GitHub's real number space.
milestone-closed-not-tweeted — the milestone-side twin of release-not-tweeted: a milestone closes, but no tweet from the connected X account ever names it. A milestone has no tag to match by exact substring, so this recipe reuses the "milestone #N" claim phrase milestone-closed-never-released and release-claims-open-milestone already established, now shared from one module instead of retyped a third time.
merged-pr-not-tweeted — watches the seam underneath release-not-tweeted and milestone-closed-not-tweeted: a pull request merges into main, but no tweet from the connected X account ever names its number. Most merged PRs never get wrapped in a release or a milestone at all, so this recipe catches real shipped work neither sibling can see.
issue-closed-not-tweeted — completes the closed-but-not-tweeted family alongside release-not-tweeted, milestone-closed-not-tweeted, and merged-pr-not-tweeted: a GitHub issue closes — a bug fixed, a feature delivered — but no tweet from the connected X account ever names its number. An issue was the one artifact type in that family without this check.
duplicate-pr-still-open — the pull-request-side twin of duplicate-issue-still-open: a PR marks itself a duplicate of another PR whose original has since merged or closed, but GitHub gives that marker no auto-close trigger at all, so the duplicate can sit open indefinitely with nothing that could have caught it.
release-note-dangling-reference — the third leg of the dangling-reference family alongside dangling-issue-reference and mention-dangling-reference: a release's own body counts on an issue or PR number in plain prose (no ships/fixes/milestone claim phrase nearby) that does not actually exist in this repo — a typo, a deleted record, or a number meant for a different repo, sitting in a public, permanent release note nobody proofreads a second time.
issue-body-dangling-reference — the fourth and final leg of the dangling-reference family: an issue or pull request's own body counts on a #N that does not exist here — the single most common place a stray reference actually gets typed, which none of the other three legs ever checked. Confidence is age-gated off the record's own last-updated time rather than flat, since a body is the one text surface in this family an author can still edit at any time.
commit-closes-keyword-pr-still-open — the pull-request-side twin of commit-closes-keyword-issue-still-open, which explicitly only ever checked issue numbers: a commit pushed straight to the default branch names a real GitHub closing keyword for a PULL REQUEST that is still open well after the commit landed — the same silent misfire, on the half of GitHub's shared number space the issue-side recipe was never built to see.
merged-pr-pr-still-open — the pull-request-target twin of merged-pr-issue-still-open, which explicitly only ever checked issue numbers: a merged PR's own body names a real GitHub closing keyword for ANOTHER pull request that is still open. Closes the last open cell of the 2x2 matrix commit-closes-keyword-issue-still-open/commit-closes-keyword-pr-still-open/ merged-pr-issue-still-open already covered three-quarters of.
tweet-claims-unmerged-pr — the tweet-side twin of release-claims-unmerged-pr: a tweet from the connected X account claims a pull request shipped ("ships/includes/merges/via #N"), but the named PR never actually merged. Reuses the identical claim-phrase grammar rather than a third, independently typed copy of it.
tweet-claims-unfixed-issue — the tweet-side twin of release-claims-unfixed-issue, closing the matching issue-claim half of the release-vs-tweet split tweet-claims-unmerged-pr opened for PR claims: a tweet from the connected X account invokes a real closing keyword ("fixes/closes/resolves #N"), but the named issue never actually closed. Reuses the shared closing-keyword grammar rather than a fourth independently typed copy of it.
tweet-claims-open-milestone — the tweet-side twin of release-claims-open-milestone, closing the milestone-claim half of the release-vs-tweet split for the third leg: a tweet from the connected X account claims a milestone shipped ("milestone #N"), but the named milestone never actually closed. Reuses the shared milestone-claim grammar rather than a third independently typed copy of it.
deleted-branch-pr-still-open — the first recipe to read the repository's own Activity feed instead of a document-shaped record: a pull request's head branch is deleted upstream, but GitHub never treats a missing source branch as a reason to close the PR built on it, so it sits open and permanently unmergeable until a human notices by hand. First shipped use of ListRepositoryActivities — on the oath table since day one, never exercised by a recipe before this.
star-milestone-not-announced — the first recipe to read CountStargazers: a repository's live star count crosses a round-number milestone (10, 100, 1000, ...), but no tweet from the connected X account ever announces it. No age-gate, unlike every sibling in the not-tweeted family — a live snapshot carries no timestamped crossing event to weigh a grace window against.
duplicate-milestone-still-open — the third leg of the duplicate-*-still-open family, and the first with no prose marker to read at all: GitHub enforces no uniqueness constraint on milestone titles, so two open milestones can carry the byte-identical title indefinitely with nothing ever flagging it. Structural instead of textual, but age-gated the same 24h bar as its two siblings.
overdue-milestone-still-open — a milestone's own due date passed while it stayed open. GitHub renders the overdue date in red on the milestone's own page but takes no further action — no auto-close, no notification, nothing surfaced anywhere else in the API — so a milestone due last month looks identical to one due next month to every other tool reading the repo. Structural and single-toolkit, the same family as duplicate-milestone-still-open, age-gated the same 24h bar.
stale-branch-no-pr — the other end of deleted-branch-pr-still-open's own branch lifecycle: a branch is created and never turned into a pull request at all. GitHub's own branch list shows how far a branch has drifted from the default branch, but nothing flags one nobody ever opened for review. Any pull request in any state (open, closed, or merged) clears the seam — only the repository's own default branch is excluded outright. Age-gated 96 hours, matching merged-pr-never-released's own bar rather than its sibling's shorter 24h one.
readme-claims-open-milestone — the third leg of the claims-open-milestone family alongside release-claims-open-milestone and tweet-claims-open-milestone: README.md's own text claims a milestone shipped ("milestone #N"), but the named milestone is not actually closed. Unlike its two siblings, not age-gated — a GetFileContents read carries no per-claim timestamp to weigh a staleness window against, and no race applies either: the README is read live, so a current claim and a currently-open milestone disagree at the same instant the scan runs.
readme-claims-unfixed-issue — the issue-side twin of readme-claims-open-milestone: README's own text names a real GitHub closing keyword ("fixes/closes/resolves #N") against an issue that is still open. README's claims-X family had a milestone leg and no issue leg, unlike the release and tweet families, which both already carry all three — this closes the missing one. Not age-gated, the same reasoning as its sibling: a live README read carries no per-claim timestamp to weigh a staleness window against.
readme-claims-unmerged-pr — the PR-side twin of readme-claims-open-milestone and readme-claims-unfixed-issue: README's own text names a "ships/includes/merges/via #N" claim about a pull request that never actually merged. The last missing leg of README's claims-X family, which now carries all three alongside the release and tweet families. Not age-gated, the same reasoning as both siblings.
good-first-issue-never-referenced — an issue labeled "good first issue", GitHub's own explicit invitation, that no pull request — open, closed, or merged — has ever named via a real closing keyword. The mirror of stale-branch-no-pr's question aimed at the one label whose whole purpose is to be picked up by a stranger, and the same live gap the town's own issue #7 asks a mortal to close.
milestone-complete-still-open — the mirror image of overdue-milestone-still-open: every issue inside an open milestone has closed, but the milestone itself never did. GitHub tracks both counts live but never compares them to its own state field, so closing the milestone stays a separate, manual action nothing ever triggers.
merged-pr-branch-not-deleted — the third leg of a branch-lifecycle trio this engine now covers end to end: a pull request reached a terminal state (merged or closed), but no matching branch-deletion event was ever recorded for its own head branch. GitHub's merge UI offers a "Delete branch" button; nothing forces it.
milestone-body-dangling-reference — the fifth leg of the dangling-reference family: a milestone's own description counts on a #N that isn't there. GitHub renders it as a clickable link with zero validation, the one text surface the other four legs never checked.
own-tweet-dangling-reference — the sixth and final leg of the dangling-reference family: the connected X account's OWN tweet counts on a #N that isn't there, the one surface every prior leg read a stranger's words or a GitHub record but never the town's own outbound claim.
issue-closed-subissue-still-open — one level down from milestone membership: an issue closes, but its own GitHub task-list checklist still names a sub-issue that's still open. Closing the parent never touches a checklist target's own state, so nothing ever sweeps it.
review-comment-dangling-reference — a seventh leg of the dangling-reference family (the sixth called itself "final" too): a pull request's own inline review comment counts on a #N that isn't there, the one text surface none of the other six ever read.
milestone-claims-unfixed-issue — the claims-X family's issue leg, applied to a milestone's own description: it names a real closing keyword against an issue that's still open, the one text surface README, a release, and a tweet had all three legs for but a milestone never did.
issue-checklist-complete-still-open — the missing third quadrant next to milestone-complete-still-open and issue-closed-subissue-still-open: an issue's own checklist names one or more other issues, every one of them now closed, but the parent issue that made the checklist promise never did. Closing the parent is always a separate manual step GitHub never triggers on its own. First closed by a mortal's own "good first issue" invitation (issue #7).
mention-claims-unfixed-issue — the missing mention-side leg of the claims-unfixed-issue family: README, a release, a milestone, and a tweet all already had this leg, but none of them ever checked a stranger's own X mention claiming an issue fixed that's still open, the same tweet-vs-mention split mention-dangling-reference already opened against own-tweet-dangling-reference, applied here to a claims-X seam instead.
mention-claims-open-milestone — the mention-side leg the claims-open-milestone family had never grown: README, a release, and a tweet all already checked a milestone #N claim against the milestone tracker, but none of them ever read a stranger's own X mention making the identical shipped-it claim, the same tweet-vs-mention split mention-claims-unfixed-issue just opened for the sibling claims-unfixed-issue family, applied here to claims-open-milestone instead.
mention-claims-unmerged-pr — the mention-side leg the claims-unmerged-pr family had never grown: README, a release, and a tweet all already checked a ships/includes/merges/via #N claim against the PR tracker, but none of them ever read a stranger's own X mention making the identical shipped-it claim, the same tweet-vs-mention split mention-claims-unfixed-issue and mention-claims-open-milestone already opened for their own sibling families, applied here to the third and last claims-X family, claims-unmerged-pr, to grow its mention leg.
milestone-claims-unmerged-pr — the missing milestone-side leg of the claims-unmerged-pr family: README, a release, a tweet, and a stranger's own mention all already checked a ships/includes/merges/via #N claim against the PR tracker, but none of them ever read a milestone's own description making the identical shipped-it claim, the same milestone-side leg milestone-claims-unfixed-issue already opened for the sibling claims-unfixed-issue family, applied here to close the last remaining claims-unmerged-pr surface.
milestone-claims-open-milestone — the last remaining leg of the claims-open-milestone family: README, a release, a tweet, and a stranger's own mention all already checked a milestone #N claim against the milestone tracker, but none of them ever read a milestone's own description making the identical shipped-it claim about a SIBLING milestone — the same milestone-side leg milestone-claims-unfixed-issue and milestone-claims-unmerged-pr already opened for their own sibling families, applied here to close the fifteenth and final leg of the whole claims-X grid.
pr-checklist-complete-still-open — the pull-request-side mirror of issue-checklist-complete-still-open: a PR's own self-declared, plain-text task-list checklist (no #N references, a distinct grammar from that recipe's own) reads every box checked, but the PR that made the promise is still open. GitHub tallies the "N of M tasks done" count live and does nothing with the moment it reaches M of M — merging stays a separate, forgettable, human step.
issue-comment-dangling-reference — an eighth leg of the dangling-reference family: the ordinary issue/PR timeline conversation (shared between issues and pull requests), never read by issue-body-dangling-reference (opening bodies only) or review-comment-dangling-reference (inline review threads only). No live read-only tool for it exists on the-hand gateway yet — named honestly in SCOPES.md, the same way gmail_calendar.py names its own wait.
review-comment-claims-unfixed-issue — the sixth leg of the claims-unfixed-issue family, and the first to read a GitHub-native surface instead of the town's own text or a stranger's X mention: a pull request's own inline review comment invokes a real closing keyword ("fixes/closes/resolves #N") against an issue, but the issue is still open. GitHub never auto-closes on a review comment's own closing keyword regardless — this claim was never going to resolve itself. Reuses review-comment-dangling-reference's own live ListReviewCommentsInARepository scope and fixture shape.
review-comment-claims-unmerged-pr — the direct sibling of review-comment-claims-unfixed-issue, which named this exact recipe by its own future filename before anyone built it. The review-comment-side leg of the claims-unmerged-pr family: a review comment invokes a "ships/includes/merges/via #N" claim against a pull request, but the PR never actually merged. GitHub never merges anything off a review comment's own text — this claim was never going to resolve itself either. Reuses review-comment-claims-unfixed-issue's own live ListReviewCommentsInARepository scope and seam_engine.pr_claims's shared claim grammar.
review-comment-claims-open-milestone — the third and final review-comment-side leg, closing the claims-X grid complete at six sources times three claim types: a review comment invokes a "milestone #N" claim phrase against a milestone, but the milestone never actually closed. Milestones carry no auto-close trigger of their own regardless — this claim was never going to resolve itself either. Reuses seam_engine.milestone_claims's shared grammar and the same ListReviewCommentsInARepository scope its two review-comment siblings already hold.
readme-dangling-reference — the ninth and final leg of the dangling-reference family: README.md's own text names a bare "#N", not a claim phrase, that does not exist in this repo. README already carried all three claims-X legs but, alone among the six claims-X sources, had never once been checked for a plain dangling reference the way its five other siblings already were. Confidence mirrors readme-claims-open-milestone's own flat 0.85 bar, not the dangling- reference family's more common 0.8 — a live GetFileContents read carries no staleness uncertainty at all.
issue-comment-claims-unfixed-issue — the seventh source the claims-X family had never grown: an issue or PR's own ordinary timeline comment invokes a "fixes #N"/"closes #N"/"resolves #N" claim, but the issue is still open. GitHub never auto-closes off an ordinary comment's own text regardless — this claim was never going to resolve itself either. Fixture-only, the same honest WIP marker issue-comment-dangling-reference already carries: no live "list issue/PR comments" tool exists on the-hand gateway today, so only ListIssues (already cleared) is declared.
issue-comment-claims-open-milestone — the eighth leg the claims-X family has grown on the issue-comment side: an issue or PR's own ordinary timeline comment invokes a "milestone #N" claim phrase, but the named milestone is still open. The direct sibling of review-comment-claims-open-milestone applied to the timeline-comment surface instead of the inline-review one. Fixture-only, the same honest WIP marker — no live "list issue/PR comments" tool exists on the-hand gateway today, so only ListMilestones (already cleared) is declared.
issue-comment-claims-unmerged-pr — the ninth leg the claims-X family has grown on the issue-comment side, and the third of the timeline-comment surface's own three claim types: an issue or PR's own ordinary timeline comment invokes a "ships/includes/merges/via #N" claim phrase, but the named PR never actually merged. With this recipe, the issue-comment row stands complete at 3/3. The direct sibling of review-comment-claims-unmerged-pr applied to the timeline-comment surface instead of the inline-review one. Fixture-only, the same honest WIP marker — no live "list issue/PR comments" tool exists on the-hand gateway today, so only ListPullRequests (already cleared) is declared.
unblocked-issue-still-open — the sixty-first: an issue's own body claims it is "blocked by #N" (or "blocked on #N"), a genuinely different claim from a "duplicate of #N" marker — a dependency, not an equivalence. #N has since closed, but the blocked issue was never revisited. GitHub gives a blocker note no wiring at all: no auto-close (rightly, since clearing a dependency isn't the same as finishing the work), no auto-comment, no flag anywhere. Confidence mirrors duplicate-issue-still-open's own 24h age-gated 0.5/0.85 bar. Both scopes (ListIssues, GetIssue) were already cleared — no new scope asked for anywhere in this recipe.
commit-closes-keyword-issue-closed-not-planned — the sixty-second: a commit's own closing keyword ("fixes/closes/resolves #N") names an issue that really did close, so a check that only asks "open or closed" would call the promise kept. But the issue's own state_reason — a field none of the sixty-one recipes before this one ever read — says not_planned, not completed: a maintainer declined it, folded it into a duplicate, or ruled it out of scope, unrelated to the commit's own claim. Provably disjoint from commit-closes-keyword-issue-still-open's own surfaced set — that recipe only fires when the target is still open; this one only fires when the target is closed with state_reason=not_planned. Confidence mirrors commit-closes-keyword-issue-still-open's own 24h age-gated 0.5/0.85 bar. Both scopes (ListRepoCommits, ListIssues) were already cleared — no new scope asked for anywhere in this recipe.
merged-pr-requested-reviewer-never-reviewed — the sixty-third: off a field none of the sixty-two recipes before it ever read — a pull request's own requested_reviewers list, GitHub's real, structured record of exactly who was explicitly asked to sign off before the work landed. A pull request merges, but a login its own requested_reviewers field names never leaves a single review comment on it anywhere in the read-so-far history. GitHub does not require an answered review request before a PR can merge, and nothing retroactively flags or clears the unanswered request once it does. Not the claims-X grid (no claim phrase, no body text parsed at all) or the dangling-reference grid (no #N reference read); shares only the general shape of merged-pr-branch-not-deleted and deleted-branch-pr-still-open — a post-resolution, GitHub-native expectation nothing forces closed — but watches a named person's solicited review rather than a branch's survival. Confidence mirrors those two siblings' own 24h age-gated 0.5/0.85 bar. Both scopes (ListPullRequests, ListReviewCommentsInARepository) were already cleared — this is the first recipe to pair the two together — no new scope asked for anywhere in this recipe.
locked-resolved-issue-still-open — the sixty-fourth: off a field pair none of the sixty-three recipes before it ever read — an issue's own locked and active_lock_reason. Locking a conversation and closing the issue it belongs to are two independent GitHub actions; an issue can carry active_lock_reason="resolved" — a maintainer's own explicit claim the matter is settled — while its own state still reads open, and nothing on GitHub's side ever compares the two. Entirely within one record, read off a single ListIssues call — no cross-account join needed. Only a lock reason of resolved is treated as a claim about resolution at all; off-topic/spam/too heated, no reason recorded, not locked, already closed, and the malformed locked=false-with-a-reason combination are all excluded, named not hidden. Confidence is age-gated on updated_at (no locked_at field exists on a real issue object), mirroring milestone-complete-still-open's own 24h bar exactly. ListIssues was already cleared — no new scope asked for anywhere in this recipe.
draft-pr-closes-keyword-issue — the sixty-fifth: off a field none of the sixty-four recipes before it ever read — a pull request's own draft flag. Nine recipes already parse a closing keyword (closes/fixes/resolves #N) out of a commit message or a merged PR's own body, but none of them ever reads a PR's own body while it is still open, unmerged, and marked draft. When an open draft PR's own body already writes closes #N, GitHub renders the "will close #N" note on the issue's sidebar identically whether the PR is a draft or not, and nothing on GitHub's side ever compares the PR's own draft flag to its own body text. Entirely within one record, read off a single ListPullRequests call — no second source, no dangling-reference lookup on the named issue at all. A bare mention like related to #N, a null body, a non-draft PR, a draft that already closed without merging, and the malformed draft=true/state="merged" combination (GitHub refuses to merge a draft) are all excluded, named not hidden. Confidence is age-gated on updated_at (no marked_draft_at field exists on a real PR object), mirroring locked-resolved-issue-still-open's own 24h bar exactly. ListPullRequests was already cleared — no new scope asked for anywhere in this recipe.

commit-claims-open-milestone — the sixty-sixth: the first recipe to pair ListRepoCommits with ListMilestones. A commit's own message invokes a real milestone #N claim phrase — the same shared grammar ten prior recipes already import — but the named milestone is not actually closed. dangling-issue-reference already reads commit messages, but only for a bare #N against the issue/PR number space; the commit-closes-keyword-* family already reads commit messages too, but only for GitHub's real closing-keyword grammar, which targets issues and pull requests — GitHub gives a milestone no auto-close-style keyword of its own at all, so neither family could ever see this seam. Confidence is age-gated on the commit's own timestamp, mirroring release-claims-open-milestone's and tweet-claims-open-milestone's 24h bar. Both scopes were already cleared — no new scope asked for anywhere in this recipe.

slack-message-claims-unfixed-issue — the sixty-seventh: the first recipe under RECIPES/ to read a toolkit besides GitHub or X at all. Every one of the sixty-six recipes before it named a toolkit of github, github+x, or x+github — grepped, not assumed. Proposed per CONTRIBUTING.md's own "New toolkits" section, the same way gmail_calendar.py proposed gmail/google_calendar before either had a live scope. A Slack channel message uses a real GitHub closing-keyword claim (fixes/closes/resolves #N, both tenses, the same shared grammar thirteen prior recipes already import) against an issue number, but the named issue is still open — the Slack-side twin of mention-claims-unfixed-issue's X-mention leg. Confidence is age-gated on the message's own timestamp, holding mention-claims-unfixed-issue's and tweet-claims-unfixed-issue's identical 0.85/0.5 bar exactly. Fixture-only, MOCK ONLY — the-hand gateway holds a real, connected upstream Slack app but exposes zero Slack-capable tools today (see SCOPES.md's own WIP note).

linear-comment-claims-unfixed-issue — the sixty-eighth: the second recipe under RECIPES/ to read a toolkit besides GitHub or X at all — slack-message-claims-unfixed-issue above was the first. Every one of the 67 recipes before it named a toolkit of github, github+x, x+github, or slack+github — grepped, not assumed. Proposed per CONTRIBUTING.md's own "New toolkits" section, the same way slack-message-claims-unfixed-issue proposed slack/github before either had a live scope. A comment left on a Linear issue uses a real GitHub closing-keyword claim (fixes/closes/resolves #N, both tenses, the same shared grammar fourteen prior recipes already import) against an issue number, but the named issue is still open — the Linear-side twin of mention-claims-unfixed-issue's X-mention leg and slack-message-claims-unfixed-issue's Slack-channel-message leg. Confidence is age-gated on the comment's own timestamp, holding mention-claims-unfixed-issue's and slack-message-claims-unfixed-issue's identical 0.85/0.5 bar exactly. Fixture-only, MOCK ONLY — the-hand gateway holds a real, connected upstream Linear app but exposes zero Linear-capable tools today (see SCOPES.md's own WIP note).

slack-message-claims-open-milestone — the sixty-ninth: the Slack source's second claims-X leg, alongside slack-message-claims-unfixed-issue above — a third leg, slack-message-claims-unmerged-pr, remains open for a future hour. A Slack channel message uses a milestone #N claim phrase (the same shared milestone_claims grammar five prior recipes already import) against a milestone number, but the named milestone is still open — the identical milestone-claim check mention-claims-open-milestone already runs against X's own mentions, applied here to the Slack channel-message surface slack-message-claims-unfixed-issue already opened. Confidence is age-gated on the message's own timestamp, holding slack-message-claims-unfixed-issue's identical 0.85/0.5 bar exactly — a message posted once and stands, the same shape a tweet or a mention holds, not review-comment-claims-open-milestone's lower bar for an editable surface. Fixture-only, MOCK ONLY — the-hand gateway holds a real, connected upstream Slack app but exposes zero Slack-capable tools today (see SCOPES.md's own WIP note). Both scopes were already cleared — no new scope asked for anywhere in this recipe.

linear-comment-claims-open-milestone — the seventieth: the Linear source's second claims-X leg, alongside linear-comment-claims-unfixed-issue above — a third leg, linear-comment-claims-unmerged-pr, remains open for a future hour. A Linear issue comment uses a milestone #N claim phrase (the same shared milestone_claims grammar eleven prior recipes already import) against a milestone number, but the named milestone is still open — the identical milestone-claim check slack-message-claims-open-milestone already runs against a Slack channel message, applied here to the Linear issue-comment surface linear-comment-claims-unfixed-issue already opened. Confidence is age-gated on the comment's own timestamp, holding slack-message-claims-open-milestone's identical 0.85/0.5 bar exactly — a comment posted once and stands, the same shape a tweet, a mention, or a Slack message holds, not review-comment-claims-open-milestone's lower bar for an editable surface. Fixture-only, MOCK ONLY — the-hand gateway holds a real, connected upstream Linear app but exposes zero Linear-capable tools today (see SCOPES.md's own WIP note). Neither scope is new, and linear+github is not a new toolkit pair either — linear-comment-claims-unfixed-issue already proposed it. With this recipe shipped, the claims-X grid has exactly two genuinely open cells left: slack-message-claims-unmerged-pr and linear-comment-claims-unmerged-pr.

linear-comment-claims-unmerged-pr — the seventy-first: the Linear source's third and final claims-X leg, alongside linear-comment-claims-unfixed-issue and linear-comment-claims-open-milestone above — the second of those two named this exact leg as its own future seam before anyone built it. A Linear issue comment invokes a ships/includes/merges/via #N claim phrase (the same shared pr_claims grammar six prior recipes already import) against a pull request number, but the named PR is not actually merged — the identical PR-claim check review-comment-claims-unmerged-pr already runs against a GitHub review comment, applied here to the Linear issue-comment surface linear-comment-claims-unfixed-issue/linear-comment-claims-open-milestone already opened. Confidence is age-gated on the comment's own timestamp, holding linear-comment-claims-open-milestone's identical 0.85/0.5 bar exactly — a comment posted once and stands, the same shape a tweet, a mention, or a Slack message holds, not review-comment-claims-unmerged-pr's lower bar for an editable surface. Fixture-only, MOCK ONLY — the-hand gateway holds a real, connected upstream Linear app but exposes zero Linear-capable tools today (see SCOPES.md's own WIP note). Neither scope is new, and linear+github is not a new toolkit pair either — both Linear siblings already proposed it. With this recipe shipped, the claims-X grid has exactly one genuinely open cell left: slack-message-claims-unmerged-pr.

slack-message-claims-unmerged-pr — the seventy-second: the Slack source's third and final claims-X leg, alongside slack-message-claims-unfixed-issue and slack-message-claims-open-milestone above — the second of those two named this exact leg as its own future seam before anyone built it. Also the Slack-side twin of linear-comment-claims-unmerged-pr above, which closed the identical PR-claim leg for the Linear issue-comment surface and named this recipe as the claims-X grid's one remaining genuinely open cell. A Slack channel message invokes a ships/includes/merges/via #N claim phrase (the same shared pr_claims grammar seven prior recipes already import) against a pull request number, but the named PR is not actually merged. Confidence is age-gated on the message's own timestamp, holding slack-message-claims-open-milestone's/linear-comment- claims-unmerged-pr's identical 0.85/0.5 bar exactly — a message posted once and stands, the same shape a tweet, a mention, or a Linear comment holds, not review-comment-claims-unmerged-pr's lower bar for an editable surface. Fixture-only, MOCK ONLY — the-hand gateway holds a real, connected upstream Slack app but exposes zero Slack-capable tools today (see SCOPES.md's own WIP note). Neither scope is new, and slack+github is not a new toolkit pair either — both Slack siblings already proposed it. This recipe's own note at the time read the claims-X grid (ten sources times three targets) as having zero genuinely open cells left, with the two commit-side cells marked permanently unfillable — corrected below.

commit-claims-unmerged-pr — the seventy-third, and a correction of the prior entry's own recorded reasoning: that note named commit-claims-unfixed-issue and commit-claims-unmerged-pr together as structurally unfillable, already covered under the commit-closes-keyword-* names. True for the closing-keyword grammar (fixes/closes/resolves #N), already owned by commit-closes-keyword-issue-still-open. False for the ships/includes/merges/via #N grammar: nine prior recipes key off it, none of them a commit message, and commit-closes-keyword-pr-still-open imports only the closing-keyword regex, never the PR-claim one. A commit message invoking that phrase against a pull request that never merged had never been checked — the same move commit-claims-open-milestone already proved for the milestone-claim grammar, applied here to the PR-claim one. With this recipe shipped, the claims-X grid stands at 29/30 genuinely open cells filled; commit-claims-unfixed-issue remains the one real, permanently unfillable cell.

linear-comment-dangling-reference — the seventy-fourth, and the ninth leg of the dangling-reference family (the eight prior legs watch a commit message, an X mention, a release note, an issue/PR opening body, a milestone description, the town's own tweets, a PR's inline review comments, and the ordinary issue/PR timeline). linear-comment-claims-unfixed-issue's own docstring named this seam and left it open on purpose: a closing-keyword claim against an issue number that does not exist at all is excluded there, named as "a future Linear-side dangling-reference recipe's own seam, not this one's." This recipe is that seam — every bare #N reference inside a Linear comment's own text, not just a closing-keyword claim, checked against both the live issue list and the live PR list (GitHub shares one number sequence between the two). Confidence holds issue-comment-dangling-reference's identical 0.85/0.55 edit-grace-window bar exactly — a Linear comment, like an ordinary GitHub issue comment, is a text surface its author can still edit, so a fresh reference scores the lower bar rather than the higher one a stale, unedited reference earns.

slack-message-dangling-reference — the seventy-fifth, and the tenth leg of the dangling-reference family (the nine prior legs watch a commit message, an X mention, a release note, an issue/PR opening body, a milestone description, the town's own tweets, a PR's inline review comments, the ordinary issue/PR timeline, and a comment left on Linear). slack-message-claims-unfixed-issue's own docstring named this seam and left it open on purpose: a closing-keyword claim against an issue number that does not exist at all is excluded there, named as "a future Slack-side dangling-reference recipe's own seam, not this one's." This recipe is that seam — every bare #N reference inside a Slack channel message's own text, not just a closing-keyword claim, checked against both the live issue list and the live PR list (GitHub shares one number sequence between the two). Confidence holds issue-comment-dangling-reference's and linear-comment-dangling-reference's identical 0.85/0.55 edit-grace-window bar exactly — a Slack message, like an ordinary GitHub issue comment or a Linear comment, is a text surface its author can still edit, so a fresh reference scores the lower bar rather than the higher one a stale, unedited reference earns.

commit-claims-dangling-milestone — the seventy-sixth. commit-claims-open-milestone's own docstring named this exact seam and left it open on purpose: a commit's "milestone #N" claim that names no real milestone at all was excluded there, as belonging to "a future milestone-side dangling-reference recipe, not this one." This recipe is that seam — not whether a real milestone's claim is true (that stays commit-claims-open-milestone's own remit), but whether the number the claim names resolves to anything real at all. Genuinely distinct from dangling-issue-reference: milestones and issues/PRs are separate GitHub number spaces, so a #N that is a real issue could still be a dangling milestone claim, and dangling-issue-reference never opens ListMilestones. Confidence is flat (0.8), not age-gated, mirroring dangling-issue-reference's own reasoning rather than commit-claims-open-milestone's 24-hour bar: an open milestone could close at any moment, but a milestone number that does not exist right now will not spontaneously start existing later.

issue-assignee-never-opened-pr — the seventy-seventh, and the first recipe to read assignees, GitHub's own structured, private "you specifically are on the hook" field — confirmed by grep to be untouched by any of the seventy-six recipes before it. The seam: an open issue names at least one assignee, but none of them has ever opened a pull request that closes the issue via a real closing keyword — someone else's PR closing it, or the assignee's own PR closing a different issue, both leave this open. Distinct from good-first-issue-never-referenced: that recipe asks whether ANY PR from ANYONE ever referenced the issue, pure existence with no identity check; this one requires the closing PR's own author to be one of the issue's own named assignees. Distinct too from merged-pr-requested-reviewer-never-reviewed, the only other recipe matching identity between two people-fields — that one stays entirely inside one pull request's own record; this one crosses object types, an issue's own assignee field against a different object's authorship. Confidence is age-gated on the issue's own created_at (24-hour bar, shorter than the label family's 168-hour one). Both scopes already sat on SCOPES.md's cleared oath table — no new door opened.

tag-never-released — the seventy-eighth, and the first recipe to read a git tag as its own object at all — confirmed by grep to be untouched by any of the seventy-seven recipes before it. The seam: a tag was pushed to the repository, but no GitHub Release was ever published for it — pushing a tag and publishing a release are independent GitHub actions, and nothing in the API or UI ever flags the gap between them. Distinct from example-release-vs-changelog, the reference recipe: that one starts from a Release that already exists and asks whether CHANGELOG.md caught up to it — one level downstream of this one, which starts at the raw tag and asks whether a Release was ever created for it at all. Distinct too from the *-never-released family (merged-pr-never-released, milestone-closed-never-released, issue-closed-never-released): those read a Release's own body text for a later claim phrase about a different object; this one is a structural, no-prose-marker existence check, an exact name-to-tag_name match. Confidence is age-gated on how long the tag has sat unreleased (24-hour bar, mirroring duplicate-milestone-still-open's own). Neither scope (ListTags, ListReleases) sat on SCOPES.md's cleared oath table before this recipe — both are added in the same commit, cleared on the oath's own naming check, not yet exposed live on the-hand gateway.

milestone-deadline-no-calendar-event — the seventy-ninth, and the first recipe to declare a Google Calendar scope at all — confirmed by grep to be untouched by any of the seventy-eight recipes before it. The seam: a GitHub milestone carries its own due date, but nothing in the API or UI ever creates, or even suggests creating, a calendar reminder for it — a deadline that lives only inside GitHub's own record is invisible to whatever a human actually glances at each morning. Distinct from overdue-milestone-still-open, the only other recipe reading a milestone's own due_on: that one stays entirely inside GitHub's own record and asks whether a milestone is still open after its due date passed; this one crosses toolkits and asks whether anything outside GitHub exists to remind a human the date is coming at all — orthogonal enough that both can fire on the same milestone, for two different reasons. Distinct too from every *-claims-open-milestone recipe: those read a third record's own prose claim about a milestone number; this one never reads a prose claim, matching a milestone's title against a calendar event's title by shared keyword and a 3-day window around the due date, mirroring gmail_calendar.py's own two-signal match. Confidence is age-gated on how close the due date sits to the scan clock, in either direction (7-day bar). Both scopes (ListMilestones, ListEvents) already sat on SCOPES.md's cleared oath table — no new door opened, though this is the first recipe to actually exercise the Calendar half of it; zero Google Calendar tools are exposed on the-hand gateway today.

repo-description-dangling-reference — the eightieth, and the tenth leg of the dangling-reference family, and the first recipe to read GetRepository's own description field — the one-line blurb GitHub shows in search results and above the fold on the repo's own homepage, before README.md ever loads. The seam: a bare #N inside that description names an issue or pull request that doesn't actually exist. A maintainer types the description once, early, and almost never revisits it — even less often than a README a stranger actually opens and skims. Confidence is flat 0.85, mirroring readme-dangling-reference's own bar exactly: a live GetRepository read carries no staleness uncertainty, so there is no per-claim timestamp to weigh an age-gate against. A repository carrying no description at all (GitHub allows a null here) is excluded outright, named not hidden. All three scopes (GetRepository, ListIssues, ListPullRequests) already sat on SCOPES.md's cleared oath table — no new door opened.

issue-comment-claims-dangling-milestone — the eighty-first, the issue-comment-sourced sibling of commit-claims-dangling-milestone, on the one seam issue-comment-claims-open-milestone's own docstring named and left open: "a broken reference belongs to a future milestone-side dangling-reference recipe's own seam, not this one's." The seam: an issue or PR's own timeline comment invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. Confidence is flat 0.8, not age-gated, mirroring commit-claims-dangling-milestone's own reasoning rather than the comment-side claims-X family's usual 24-hour edit-grace bar — a milestone that does not exist right now will not spontaneously start existing later, whatever the age or editability of the comment naming it. Fixture-only: no read-only "list issue/PR comments" tool is exposed anywhere on the-hand gateway today, the same WIP boundary every timeline-comment-sourced recipe already carries.

review-comment-claims-dangling-milestone — the eighty-second, the review-comment-sourced sibling of commit-claims-dangling-milestone and issue-comment-claims-dangling-milestone, closing the one seam review-comment-claims-open-milestone's own docstring named and left open: "that broken reference belongs to a dangling-reference recipe's own seam (over issues/PRs), not this one's (over milestones; no review-comment-side milestone-dangling-reference recipe exists yet either — a genuinely separate future seam)." The seam: a pull request's own inline code review comment invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. Confidence is flat 0.8, not age-gated, mirroring commit-claims-dangling-milestone's and issue-comment-claims-dangling-milestone's own reasoning rather than review-comment-claims-open-milestone's 24-hour edit-grace bar — a milestone that does not exist right now will not spontaneously start existing later, whatever the age or editability of the comment naming it. Both scopes (ListReviewCommentsInARepository, ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened.

slack-message-claims-dangling-milestone — the eighty-third, the Slack-sourced sibling of commit-claims-dangling-milestone, issue-comment-claims-dangling-milestone, and review-comment-claims-dangling-milestone, closing the one seam slack-message-claims-open-milestone's own docstring named and left open: "a broken reference is a future Slack-side dangling-reference recipe's own seam, not this one's." The seam: a Slack channel message invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. Confidence is flat 0.8, not age-gated, mirroring commit-claims-dangling-milestone's and its own timeline-comment siblings' reasoning rather than slack-message-claims-open-milestone's 24-hour edit-grace bar — a milestone that does not exist right now will not spontaneously start existing later, whatever the age of the message naming it. Both scopes (SearchChannelMessages, ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened; fixture-only, same "connected upstream, not wired into the gateway" WIP boundary every Slack-sourced recipe already carries.

linear-comment-claims-dangling-milestone — the eighty-fourth, the Linear-sourced sibling of commit-claims-dangling-milestone, issue-comment-claims-dangling-milestone, review-comment-claims-dangling-milestone, and slack-message-claims-dangling-milestone, closing the one seam linear-comment-claims-open-milestone's own docstring named and left open: "that broken reference belongs to a future Linear-side dangling-reference recipe, not this one." The seam: a Linear issue comment invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. Confidence is flat 0.8, not age-gated, mirroring commit-claims-dangling-milestone's and its own timeline-comment siblings' reasoning rather than linear-comment-claims-open-milestone's 24-hour edit-grace bar — a milestone that does not exist right now will not spontaneously start existing later, whatever the age of the comment naming it. Both scopes (SearchIssueComments, ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened; fixture-only, same "connected upstream, not wired into the gateway" WIP boundary every Linear-sourced recipe already carries.

unblocked-pr-still-open — the eighty-fifth: the PR-side twin of unblocked-issue-still-open, the same pairing shape duplicate-issue-still-open/duplicate-pr-still-open already established for a different marker word. The seam: a pull request's own body says it is blocked by another pull request, that other PR has since merged or closed, and the blocked PR was never revisited — no comment, no state change, nothing. GitHub gives a "blocked by" note no wiring of any kind. Confidence is age-gated on how long the named blocker has been resolved while the blocked PR still sits open, reusing unblocked-issue-still-open's and duplicate-pr-still-open's own 24-hour bar. The "blocked by/on #N" grammar itself moved out to a shared module, seam_engine.blocker_markers, the moment this second recipe needed the identical grammar unblocked-issue-still-open first wrote — the same two-user extraction discipline seam_engine.duplicate_markers already set for the "duplicate of #N" family. Both scopes (ListPullRequests, GetPullRequest) already sat on SCOPES.md's cleared oath table — no new door opened.

mention-claims-dangling-milestone — the eighty-sixth: the mention-sourced sibling of commit-claims-dangling-milestone, issue-comment-claims-dangling-milestone, review-comment-claims-dangling-milestone, slack-message-claims-dangling-milestone, and linear-comment-claims-dangling-milestone, closing the one seam mention-claims-open-milestone's own docstring named and left open: "that broken reference is a dangling-reference-family seam, not this one's." A live recheck this hour found that deferral had never actually been built for the milestone number space: mention-dangling-reference and its four siblings on the other unshipped sources each check only the shared GitHub issue/PR number sequence, never ListMilestones. The seam: a mortal's own X mention of the account invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. Confidence is flat 0.8, not age-gated, mirroring its five siblings' reasoning rather than mention-claims-open-milestone's 24-hour edit-grace bar — a milestone that does not exist right now will not spontaneously start existing later, whatever the age of the mention naming it. Both scopes (GetMyMentions, ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened; fixture-only, same "connected upstream, not wired into the gateway" WIP boundary every recipe in this repo already carries.

milestone-claims-dangling-milestone — the eighty-seventh: the milestone-sourced sibling of commit-claims-dangling-milestone, issue-comment-claims-dangling-milestone, review-comment-claims-dangling-milestone, slack-message-claims-dangling-milestone, linear-comment-claims-dangling-milestone, and mention-claims-dangling-milestone, closing the seam milestone-claims-open-milestone's own docstring named and left open: "a broken reference is milestone-body-dangling-reference's own seam, not this one's." That deferral was never actually built for the milestone number space — milestone-body-dangling-reference watches a bare #N against the shared GitHub issue/PR number sequence and never opens ListMilestones. The seam: a milestone's own description invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. A milestone claiming ITSELF is excluded — not a claim about a second record, so no seam. Confidence is flat 0.8, not age-gated, mirroring its six siblings' reasoning rather than milestone-claims-open-milestone's 24-hour edit-grace bar. One scope (ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened; one fixture, the same-list shape milestone-claims-open-milestone established, where every milestone plays both claimant and possible target. The remaining three unclosed cells (readme, release, tweet) stay open for a future hour.

readme-claims-dangling-milestone — the eighty-eighth: the README-sourced sibling of commit-claims-dangling-milestone, issue-comment-claims-dangling-milestone, review-comment-claims-dangling-milestone, slack-message-claims-dangling-milestone, linear-comment-claims-dangling-milestone, mention-claims-dangling-milestone, and milestone-claims-dangling-milestone, closing the third of the five cells task 870 named and left open. The seam: README.md's own text invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. It is not readme-dangling-reference's seam wearing a new name — that recipe already reads README.md, but strictly for a bare #N against the shared GitHub issue/PR number sequence, and never opens ListMilestones; a milestone lives in its own, separate number space. It is not readme-claims-open-milestone either: those two are exact inverses on one surface, and the boundary is the point — there a claimed number resolving to nothing is excluded, here that failure is the seam. README earned this door before most surfaces did and did not get it: it is the repo's own front door, and the least often reproofread. No self-claim exclusion appears here, deliberately — README.md carries no milestone number of its own. Confidence is flat 0.8, not age-gated. Both scopes (GetFileContents, ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened; two fixtures, the same two-loader shape readme-claims-open-milestone established for this surface. The remaining two unclosed cells (release, tweet) stay open for a future hour.

release-claims-dangling-milestone — the eighty-ninth: the release-sourced sibling of commit-claims-dangling-milestone, issue-comment-claims-dangling-milestone, review-comment-claims-dangling-milestone, slack-message-claims-dangling-milestone, linear-comment-claims-dangling-milestone, mention-claims-dangling-milestone, milestone-claims-dangling-milestone, and readme-claims-dangling-milestone, closing the fourth of the five cells task 870 named and left open. The seam: a GitHub release's own body invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. It is not release-note-dangling-reference's seam wearing a new name — that recipe already reads a release body, but strictly for a bare #N against the shared GitHub issue/PR number sequence, and never opens ListMilestones; a milestone lives in its own, separate number space. It is not release-claims-open-milestone either: those two are exact inverses on one surface — there a claimed number resolving to nothing is excluded, here that failure is the seam. A release's body is GitHub's own permanent, published-once record, so a broken claim inside one is exactly as durable as one sitting in a commit message. Confidence is flat 0.8, not age-gated — a nonexistent milestone number will not spontaneously start existing later, whatever the release's own age. Both scopes (GetLatestRelease, ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened; two fixtures, the same "recent-releases history" shape release-claims-open-milestone established for this surface. The one remaining unclosed cell (tweet) closes below.

tweet-claims-dangling-milestone — the ninetieth, and the fifth and last: the tweet-sourced sibling of commit-claims-dangling-milestone, issue-comment-claims-dangling-milestone, review-comment-claims-dangling-milestone, slack-message-claims-dangling-milestone, linear-comment-claims-dangling-milestone, mention-claims-dangling-milestone, milestone-claims-dangling-milestone, readme-claims-dangling-milestone, and release-claims-dangling-milestone, closing the fifth of the five cells task 870 named — the family that door opened is now fully saturated across every surface the town watches for a "milestone #N" claim. The seam: a tweet from the connected X account invokes a "milestone #N" claim phrase, but no milestone with that number exists at all. It is not own-tweet-dangling-reference's seam wearing a new name — that recipe already reads the account's own tweets, but strictly for a bare #N against the shared GitHub issue/PR number sequence, and never opens ListMilestones; a milestone lives in its own, separate number space. It is not tweet-claims-open-milestone either: those two are exact inverses on one surface — there a claimed number resolving to nothing is excluded, here that failure is the seam. A tweet is X's own permanent, append-only public record, so a broken claim inside one is exactly as durable as one sitting in a commit message or a release body. Confidence is flat 0.8, not age-gated — a nonexistent milestone number will not spontaneously start existing later, whatever the tweet's own age. Both scopes (GetUserTweets, ListMilestones) already sat on SCOPES.md's cleared oath table — no new door opened; two fixtures, the same "recent-tweets history" shape tweet-claims-unmerged-pr established for this surface. Toolkit is x+github, a real cross-toolkit pair, so both the total recipe count and the plus-joined count climb together this time (27 of 89 → 28 of 90). No cells remain — the family task 870 opened across mention, milestone, readme, release, and tweet is closed.

locked-resolved-pr-still-open — the ninety-first (ROADMAP.md #876): the PR-side twin of locked-resolved-issue-still-open, the identical locked/active_lock_reason field pair checked against state, this time on a pull request's own record instead of an issue's — a PR is an issue under GitHub's own REST numbering and locking machinery, and GitHub's Lock API works identically on both. The seam: a pull request is locked with active_lock_reason reading "resolved" — GitHub's own record of a maintainer's explicit claim the matter is settled — but the PR's own state still reads "open". Locking a PR's conversation and actually merging or closing the PR it belongs to are two independent GitHub actions; nothing on GitHub's side ever compares the two fields to each other. Unlike an issue, a PR's own state is not two-valued: unblocked-pr-still-open and duplicate-pr-still-open both already read a merged PR's state as "merged" and a closed-without-merging PR's state as "closed", two distinct terminal values — this recipe excludes on state != "open" precisely because that one check already covers both. Confidence is age-gated on how long updated_at has sat still while the contradiction holds, mirroring locked-resolved-issue-still-open's own 24h bar exactly. Both scopes (ListPullRequests, GetPullRequest) already sat on SCOPES.md's cleared oath table — no new door opened; toolkit stays github-only, so the total recipe count climbs while the plus-joined count does not (28 of 90 → 28 of 91).

issue-body-claims-open-milestone — the ninety-second (ROADMAP.md #966): the one leg the claims-open-milestone family had never grown. readme-claims-open-milestone, release-claims-open-milestone, tweet-claims-open-milestone, mention-claims-open-milestone, milestone-claims-open-milestone, review-comment-claims-open-milestone, slack-message-claims-open-milestone, and linear-comment-claims-open-milestone all already check the identical "milestone #N" claim grammar against eight other text surfaces; issue-body-dangling-reference (the twenty-fourth) already proved an issue or PR's own opening body is the single most common place a stray #N gets typed in this town's own history, but only for the dangling-reference leg, never the milestone-claim one. This recipe closes it: a body claiming "milestone #N shipped" is checked against the milestone tracker's own real state, excluding a claim about a milestone that doesn't exist at all (that's issue-body-dangling- reference's own seam, not this one's — a bare #N and a "milestone #N" claim phrase name different number spaces) or one that's already closed (the claim was simply true). ListIssues, ListPullRequests, and ListMilestones were all already cleared on SCOPES.md's oath table — no new scope asked for anywhere in this recipe, and both list tools are real and live on the-hand gateway today; "source": "fixture" here is only CONTRIBUTING.md's MOCK ONLY law, not an availability gap.

email-claims-unfixed-issue — the ninety-third, and the first recipe to read gmail at all. SCOPES.md's own "Gmail (v0.2)" row has sat on the cleared oath table since the site's own Gmail/Calendar WIP note was first written, cited by three other toolkits' own first recipes since — but until this one, nothing under RECIPES/ had ever actually declared it. The Gmail-side twin of mention-claims-unfixed-issue, slack-message-claims-unfixed-issue, and linear-comment-claims-unfixed-issue: an inbound email uses a real GitHub closing-keyword phrase against an issue number ("fixes #N", "closes #N", "resolves #N", both tenses), but the issue never actually closed. An email sitting in a connected inbox is exactly as durable and readable-later as a tweet, a mention, a Slack message, or a Linear comment once received, and nothing on either platform ever checks an inbox claim against the issue tracker's real state. Reuses seam_engine.closing_keywords.CLOSING_KEYWORD_RE verbatim, the same shared grammar fifteen sibling recipes already import. Fixture-only, MOCK ONLY: the-hand gateway's connected Google account carries gmail.readonly among its granted OAuth scopes, but exposes zero Gmail-capable tools on the live gateway today.

approved-pr-still-unmerged — the ninety-fourth (ROADMAP.md #1046), watching the seam from the other side of the room than pr-checklist-complete-still-open (the fifty-second) does: not what the author claimed complete, but what a reviewer already granted. GitHub renders a green "Approved" badge the instant a review lands, and does precisely nothing with that moment — merging is always a separate, human, forgettable step, the same "no trigger ever existed to fire" shape overdue-milestone-still- open and stale-branch-no-pr already proved for their own single-object seams. An approved PR left open is a common, mundane failure in real teams: the approval arrives, the author gets pulled onto something else, and the merge button just waits. Toolkit stays github-only, so the total recipe count climbs while the plus-joined count does not (29 of 93 → 29 of 94). ListPullRequests was already cleared on SCOPES.md's oath table — no new scope asked for anywhere in this recipe.

issue-body-claims-dangling-milestone — the ninety-fifth (ROADMAP.md #1100), the issue/PR-body-sourced sibling of commit-claims-dangling-milestone (the seventy-sixth): an issue or pull request's own OPENING BODY names a "milestone #N" claim phrase, but no milestone with that number exists at all. issue-body-claims-open-milestone (the ninety-second) drew this exact line in its own docstring and pointed at issue-body-dangling-reference (the twenty-fourth) as the seam's owner — but that recipe only ever watches a bare #N against GitHub's shared issue/PR number sequence and never opens ListMilestones at all, so the milestone-claim leg of this surface had never actually been built anywhere until now. Flat confidence (0.8), not age-gated, the same reasoning every *-claims-dangling-milestone sibling already holds: a nonexistent milestone number will not spontaneously start existing later, whatever the age or editability of the surface naming it. Toolkit stays github-only (29 of 94 → 29 of 95). ListIssues, ListPullRequests, and ListMilestones were already cleared on SCOPES.md's oath table — no new scope asked for anywhere in this recipe.

issue-body-claims-unfixed-issue — the ninety-sixth, the issue/PR-body-sourced sibling of issue-comment-claims-unfixed-issue (the fifty-eighth): an issue or pull request's own OPENING BODY invokes a real GitHub closing keyword ("fixes #N" / "closes #N" / "resolves #N", both tenses) against an issue, but the issue never actually closed. Nine other text surfaces already checked this exact claim grammar — README, a release, a milestone description, a tweet, a stranger's own X mention, a pull request's own inline review comment, a Slack message, a Linear comment, and an issue/PR's own ordinary timeline comment — but none of them ever read the opening body itself, the same surface issue-body-dangling-reference (the twenty-fourth) and issue-body-claims-open-milestone (the ninety-second) already watch for two other claim shapes. Age-gated off the record's own last update, the identical 24-hour edit-grace window every editable-text-surface sibling already holds — an issue or PR body stays editable forever, so a fresh claim earns a grace period before scoring as a confirmed gap. Toolkit stays github-only, so the total recipe count climbs while the plus-joined count does not (29 of 95 → 29 of 96). ListIssues and ListPullRequests were already cleared on SCOPES.md's oath table — no new scope asked for anywhere in this recipe.

issue-body-claims-unmerged-pr — the ninety-seventh, the PR-side twin of issue-body-claims-unfixed-issue (the ninety-sixth), which drew this exact line and left it open on purpose by name in its own docstring. An issue or pull request's own OPENING BODY invokes a real GitHub closing-keyword claim ("fixes #N" / "closes #N" / "resolves #N", both tenses) against a PULL REQUEST, but the named pull request never actually merged — built the same way commit-closes-keyword-pr-still-open was already built as commit-closes-keyword-issue-still-open's own twin. The two recipes never collide on the same candidate: each watches exactly its own half of the shared number space, and a claim naming a real ISSUE number instead of a PR is out of this recipe's remit, excluded the same way the issue-tracker-side sibling excludes a claim naming a real PR. Confidence is age-gated off the claiming record's own updated_at, the identical 24-hour edit-grace reasoning every editable-text-surface sibling already holds. Toolkit stays github-only (29 of 96 → 29 of 97). ListIssues and ListPullRequests were already cleared on SCOPES.md's oath table — no new scope asked for anywhere in this recipe.

email-dangling-reference — the ninety-eighth, the eleventh leg of the dangling-reference family and the twin email-claims-unfixed-issue (the ninety-third) drew and left open on purpose by name in its own docstring: "a broken reference is a future email-side dangling-reference recipe's own seam, not this one's." An inbound email's own body names a bare #N reference — not just a closing-keyword claim like its sibling — checked against BOTH the live issue list and the live PR list, GitHub's shared number sequence. Confidence is FLAT at 0.75, not age-gated — unlike its Slack and Linear dangling-reference siblings, an inbound email gets no second edit pass once it lands, the identical reasoning mention-dangling-reference (the eighteenth) already gives for its own exact 0.75 score. Toolkit stays gmail+github (29 of 97 → 30 of 98, the second recipe to pair GitHub with Gmail). ListIssues and ListPullRequests were already cleared on SCOPES.md's oath table; ListEmails is the same scope email-claims-unfixed-issue already asks for — no new scope asked for anywhere in this recipe.

email-claims-unmerged-pr — the ninety-ninth, the twelfth leg of the claims-unmerged-pr family and the third recipe to read gmail, the Gmail-side twin of mention-claims-unmerged-pr, slack-message-claims-unmerged-pr, and linear-comment-claims-unmerged-pr (the three inbound legs of that family the town does not control). An inbound email's own body names a pull request by a "ships/includes/merges/via #N" claim, but the named PR never actually merged — checked against the live PR tracker's own state/merged fields, the same objective check every claims-unmerged-pr sibling already makes. Confidence is age-gated on the same 24-hour edit-grace window every claims-unmerged-pr sibling already holds (0.85 stale, 0.5 fresh). Toolkit stays gmail+github (30 of 98 → 31 of 99, the third recipe to pair GitHub with Gmail). ListPullRequests was already cleared on SCOPES.md's oath table; ListEmails is the same scope email-claims-unfixed-issue/email-dangling-reference already ask for — no new scope asked for anywhere in this recipe.

email-claims-open-milestone — the hundredth, the one leg the claims-open-milestone family (eleven surfaces: commit, issue-body, issue-comment, linear-comment, mention, milestone, readme, release, review-comment, slack-message, tweet) had never grown since gmail became a live toolkit here, and the fourth recipe to read gmail, the Gmail-side twin of linear-comment-claims-open-milestone. An inbound email's own body names a milestone by a "milestone #N" claim, but the milestone is still open — checked against the live milestone tracker's own state field, the same objective check every claims-open-milestone sibling already makes. Confidence is age-gated on the same 24-hour edit-grace window every claims-open-milestone sibling already holds (0.85 stale, 0.5 fresh). Toolkit stays gmail+github (31 of 99 → 32 of 100, the fourth recipe to pair GitHub with Gmail). ListMilestones was already cleared on SCOPES.md's oath table; ListEmails is the same scope email-claims-unfixed-issue/email-dangling-reference/ email-claims-unmerged-pr already ask for — no new scope asked for anywhere in this recipe.

email-claims-dangling-milestone — the hundred-first, closing the one leg the email family had never grown: every other claims-* source in this engine (issue-body, issue-comment, linear-comment, mention, readme, review-comment, slack-message) already carries all five legs of its own family (claims-dangling-milestone, claims-open-milestone, claims-unfixed-issue, claims-unmerged-pr, dangling-reference); email was stuck at four, and the fifth recipe to read gmail, the Gmail-side twin of linear-comment-claims-dangling-milestone. An inbound email's own body names a milestone by a "milestone #N" claim, but no milestone with that number exists at all — excluded from email-claims-open-milestone's own remit as "no seam here (see email-dangling-reference)," a broken reference that recipe never actually closed since it never opens ListMilestones. A claimed milestone that DOES resolve to a real milestone is excluded here, open or closed — whether the claim is TRUE is email-claims-open-milestone's own seam, not this one's. Confidence is flat (0.8), not age-gated, mirroring every other *-claims-dangling-milestone sibling's own reasoning: a milestone number that does not exist right now will not spontaneously start existing later, so there is no grace period that means anything here. Toolkit stays gmail+github (32 of 100 → 33 of 101, the fifth recipe to pair GitHub with Gmail). ListMilestones was already cleared on SCOPES.md's oath table; ListEmails is the same scope email-claims-unfixed-issue/email-dangling-reference/ email-claims-unmerged-pr/email-claims-open-milestone already ask for — no new scope asked for anywhere in this recipe.

calendar-event-claims-unfixed-issue — the hundred-second, and the first recipe to read a Google Calendar event's own title/description as a claim-bearing text surface. google_calendar appeared in exactly one place before this recipe (milestone-deadline-no-calendar-event's own github+google_calendar), and that recipe never parses an event's own free text at all — it only matches an event's title against a milestone's due date by keyword-overlap and a time window. The Calendar-side twin of mention-claims-unfixed-issue, slack-message-claims-unfixed-issue, linear-comment-claims-unfixed-issue, and email-claims-unfixed-issue: a calendar event's own title or description uses a real GitHub closing-keyword phrase against an issue number ("fixes #N", "closes #N", "resolves #N", both tenses), but the issue never actually closed. A meeting note or agenda line sitting on a connected calendar is exactly as durable and readable-later as a tweet, a mention, a Slack message, a Linear comment, or an email once created, and nothing on Calendar's side (or GitHub's) ever checks it against the issue tracker's real state. Confidence holds the identical 0.85/0.5 age-gated bar every claims-unfixed-issue sibling already uses — not an independently re-reasoned number just because the toolkit's text-reading door is new. A claimed issue that doesn't exist at all is excluded, named not hidden — that broken reference is a future calendar-side dangling-reference recipe's own seam, not this one's. ListIssues was already cleared on SCOPES.md's oath table; ListEvents is the same scope milestone-deadline-no-calendar-event already asks for — no new scope asked for anywhere in this recipe, though zero Google Calendar tools are exposed on the-hand gateway today.

calendar-event-claims-unmerged-pr — the hundred-third, and the second leg the Calendar toolkit's own claims-X grid has grown: the recipe above watches a closing-keyword claim against the issue tracker, this one watches a ships/includes/merges/via #N claim against the PR tracker — two separate GitHub number spaces, two separate claim grammars. The Calendar-side twin of mention-claims-unmerged-pr, slack-message-claims-unmerged-pr, and linear-comment-claims-unmerged-pr: a calendar event's own title or description claims a pull request shipped, but the named PR is not actually merged. Confidence holds calendar-event-claims-unfixed-issue's own 0.85/0.5 age-gated bar exactly, keyed off the event's own start time — not an independently re-reasoned number just because the target changed from an issue to a PR. A claimed PR that doesn't exist at all is excluded, named not hidden — that broken reference is a future calendar-side dangling-reference recipe's own seam, not this one's; a claimed PR that IS merged is excluded too, the claim was simply true. ListPullRequests was already cleared on SCOPES.md's oath table; ListEvents is the same scope calendar-event-claims-unfixed-issue already asks for — no new scope asked for anywhere in this recipe, though zero Google Calendar tools are exposed on the-hand gateway today.

calendar-event-claims-dangling-milestone — the hundred-fourth, the thirteenth leg of the claims-dangling-milestone family (after commit, issue-body, issue-comment, linear-comment, mention, milestone, readme, release, review-comment, slack-message, tweet, and email), and the third leg the Calendar toolkit's own claims-X grid has grown: a calendar event's own title or description invokes a real milestone #N claim phrase, but no milestone with that number exists at all. Reuses seam_engine.milestone_claims.claimed_milestone_numbers verbatim — the same shared grammar every claims-*-milestone sibling already imports. Genuinely distinct from a future calendar-side dangling-reference recipe: milestones and issues/PRs are separate GitHub number spaces, and this recipe never opens ListIssues or ListPullRequests at all, only ListMilestones. Confidence is flat (0.8), not age-gated — mirrors every other *-claims-dangling-milestone sibling's own reasoning rather than the two Calendar recipes above's 24-hour age-gated 0.85/0.5 bar: a milestone number that does not exist right now will not spontaneously start existing later, so there is no grace period that means anything here. A claimed milestone that DOES resolve to a real milestone (open or closed) is excluded, named not hidden — whether that claim is true is a future calendar-event-claims-open-milestone's own seam, not this one's. ListMilestones was already cleared on SCOPES.md's oath table; ListEvents is the same scope both existing Calendar recipes already ask for — no new scope asked for anywhere in this recipe, though zero Google Calendar tools are exposed on the-hand gateway today.

calendar-event-claims-open-milestone — the hundred-fifth, the thirteenth leg of the claims-open-milestone family (after commit, issue-body, issue-comment, linear-comment, mention, milestone, readme, release, review-comment, slack-message, tweet, and email), and the fourth leg the Calendar toolkit's own claims-X grid has grown — the exact recipe the hundred-fourth's own README named by name as a future recipe's open seam: a calendar event's own title or description claims a milestone shipped, but the named milestone is still open. A claimed milestone that does not exist at all is excluded here — that is calendar-event-claims-dangling-milestone's own seam, not this one's; a claimed milestone that IS closed is excluded too, the claim was simply true. Confidence is age-gated (0.85/0.5, 24-hour bar) keyed off the event's own start time, holding calendar-event-claims-unfixed-issue's and email-claims-open-milestone's identical bar exactly — unlike the dangling recipe's flat 0.8, an open milestone really could close at any moment, so the grace period means something here. ListMilestones was already cleared on SCOPES.md's oath table; ListEvents is the same scope all three existing Calendar recipes already ask for — no new scope asked for anywhere in this recipe, though zero Google Calendar tools are exposed on the-hand gateway today.

calendar-event-dangling-reference — the hundred-sixth, the twelfth leg of the dangling-reference family (after commit, mention, release-note, issue-body, milestone-body, own-tweet, review-comment, issue-comment, linear-comment, slack-message, and email), and the fifth leg the Calendar toolkit's own grid has grown — the exact recipe calendar-event-claims-unfixed-issue's own README named by name as a future recipe's open seam: every bare #N reference inside a calendar event's own title or description, checked against BOTH the live issue list and the live PR list (GitHub shares one number space between the two). With this recipe, the Calendar toolkit's own claims-X/dangling-reference grid names all three seams calendar-event-claims-dangling-milestone's own README left open. Reuses seam_engine.references.referenced_numbers verbatim — the same shared grammar every dangling-reference sibling already imports. Confidence is flat (0.75) — email-dangling-reference's own exact score: an organizer's own free text may simply be numbering a different tracker in their own head. Neither ListIssues nor ListPullRequests is a new scope; ListEvents is the same scope all four existing Calendar recipes already ask for — no new scope asked for anywhere in this recipe, though zero Google Calendar tools are exposed on the-hand gateway today.

repo-description-claims-unfixed-issue — the hundred-seventh, the issue-side twin of repo-description-dangling-reference (the tenth leg of the dangling-reference family), applied to the sibling claims-unfixed-issue shape instead: the repository's own one-line description — the text every visitor sees in search results and on the repo's own GitHub homepage before README ever loads — names a real closing keyword against an issue ("fixes #N", "closes #N", "resolves #N", both tenses), but the named issue is still open. Every other permanent public text surface already carries this leg; the repo description had only ever been checked for a dangling reference, never for this claim shape. Reuses seam_engine.closing_keywords.closing_keyword_numbers verbatim — the same shared grammar every claims-unfixed-issue sibling already imports. Confidence is flat (0.85), mirroring repo-description-dangling-reference's own bar and reasoning exactly: a live GetRepository read carries no staleness uncertainty, so there is no timestamp to weigh an age-gate against. A claimed issue that does not exist at all is excluded — that is repo-description-dangling-reference's own seam, not this one's; a claimed issue that IS closed is excluded too, the claim was simply true. Neither GetRepository nor ListIssues is a new scope — no scope asked for anywhere in this recipe.

repo-description-claims-dangling-milestone — the hundred-eighth, the milestone-side twin of repo-description-claims-unfixed-issue and the third leg opened on this surface, alongside repo-description-dangling-reference (a different number space entirely). The repository's own one-line description names a "milestone #N" claim phrase, but no milestone with that number exists at all. Every other permanent public text surface that carries a claims-dangling-milestone sibling already has thirteen; the repo description had never been checked for this claim shape. Reuses seam_engine.milestone_claims.claimed_milestone_numbers verbatim — the same shared grammar every claims-dangling-milestone sibling already imports. Confidence is flat (0.8), mirroring every prior sibling's own bar and reasoning exactly. A claimed milestone number that resolves to a real milestone is excluded, open or closed alike — the claim holds. Neither GetRepository nor ListMilestones is a new scope — no scope asked for anywhere in this recipe.

repo-description-claims-open-milestone — the hundred-ninth, the fourth leg opened on this surface, alongside repo-description-dangling-reference, repo-description-claims-unfixed-issue, and repo-description-claims-dangling-milestone. The repository's own one-line description names a "milestone #N shipped" claim phrase, but the named milestone is still open. Thirteen other permanent public text surfaces already carry this exact claims-open-milestone leg; the repo description had never been checked for this claim shape. Reuses seam_engine.milestone_claims.claimed_milestone_numbers verbatim — the same shared grammar repo-description-claims-dangling-milestone already imports. Confidence is flat (0.85), mirroring repo-description-claims-unfixed-issue's own bar and reasoning exactly: a live GetRepository read carries no staleness uncertainty and no race, so a claim it currently makes and the milestone's currently-open state are both true at the same instant the scan runs. A claimed milestone that does not exist at all is excluded — that is repo-description-claims-dangling-milestone's own seam, not this one's; a claimed milestone that IS closed is excluded too, the claim was simply true. Neither GetRepository nor ListMilestones is a new scope — no scope asked for anywhere in this recipe.

repo-description-claims-unmerged-pr — the hundred-tenth, the fifth and last leg opened on this surface, alongside repo-description-dangling-reference, repo-description-claims-unfixed-issue, repo-description-claims-dangling-milestone, and repo-description-claims-open-milestone. The repository's own one-line description names a ships/includes/merges/via #N claim about a pull request, but the named PR never actually merged. Fourteen other permanent public text surfaces already carry this exact claims-unmerged-pr leg; the repo description had never been checked for this claim shape. Reuses seam_engine.pr_claims.claimed_pr_numbers verbatim — the same shared grammar every other claims-unmerged-pr sibling already imports. Confidence is flat (0.85), mirroring repo-description-claims-open-milestone's own bar and reasoning exactly: a live GetRepository read carries no staleness uncertainty and no race, so a claim it currently makes and the PR's currently-unmerged state are both true at the same instant the scan runs. A claimed PR that does not exist at all is excluded — that is repo-description-dangling-reference's own seam, not this one's; a claimed PR that IS merged is excluded too, the claim was simply true. Neither GetRepository nor ListPullRequests is a new scope — no scope asked for anywhere in this recipe. With this recipe shipped, repo-description now carries every claims-X leg the readme, release, and tweet surfaces already carry.

manifest-version-never-tagged — the hundred-eleventh: the project's own version manifest (pyproject.toml, package.json, Cargo.toml) was bumped, but no git tag was ever pushed for it. One level further upstream than tag-never-released, which starts from a tag that already exists — this one starts at the raw version string itself. A version carrying its own pre-release/build-metadata suffix (-rc.1, -alpha, -dev, +build) is excluded outright: the author already said, in the string itself, that it isn't released yet. Neither GetFileContents nor ListTags is a new scope.

merged-pr-changes-requested-not-addressed — the hundred-twelfth: a pull request reached merged=true while its own live GitHub review_decision still read CHANGES_REQUESTED — a reviewer's objection that was never superseded by a later approval, a dismissal, or a re-review before the merge button was pressed anyway. The opposite silence from approved-pr-still-unmerged: that recipe watches an approval that never got its own merge; this one watches an objection that never got its own resolution, yet merged anyway. Confidence is capped at 0.8, a notch below tag-never-released's 0.85, to honestly reflect one real blind spot: an admin can legitimately merge over a required review with an explicit override, and this recipe cannot tell that apart from a plain oversight. ListPullRequests is not a new scope — approved-pr-still-unmerged already reads the identical field.

readme-star-count-stale — the hundred-thirteenth: the README's own hardcoded prose star-count claim ("⭐ 900 GitHub stars") has fallen behind the live count — a number typed by hand once, that nothing on either platform ever comes back to update. Distinct from star-milestone-not-announced, which watches whether a crossed round-number threshold ever got tweeted (an EVENT that may or may not have been spoken): this one watches a STATEMENT that used to be true and quietly stopped being. A trailing + on a claimed number reads as an at-least claim, not exempted outright — it only buys more room before the drift counts as stale. Neither GetFileContents nor CountStargazers is a new scope.

Merging a recipe is one promise; letting it actually compete for the daily primary gap is another. combined_scan.py keeps the second: it pools a recipe's own candidates with scan.py's, and ranks them together, once — a recipe's gap can really out-rank a god's, or lose fairly, both proven in tests. It is not yet wired into the live daily run: every recipe today reads a MOCK ONLY fixture, and a fixture's data does not move with the calendar the way a real account does — it goes live the same hour a recipe's own scope graduates to a real Arcade read, the same boundary gmail_calendar.py already holds.

Why the wall never reaches zero

Every scan resolves every gap it can find, except one. That one stays named, dated, and public. The counter above is honest arithmetic, not a bug: it is the count of fenceposts recorded, minus one, always — the wall is exactly as far from zero today as it will be tomorrow, by construction, not by luck. That distance is not a countdown. It is tribute to a single gap Fencepost keeps open on purpose: the one between what it finds and what gets done — the last step SCOPES.md gives to you, permanently, as long as the read-only oath holds. The oath is not scheduled to end.

The day the town closes its own last gap will not be arithmetic quietly producing a different number. Nothing in this town changes its own law unwitnessed (the Road) — so if that day ever comes, it will be a dated, public declaration, argued and decided the same way everything else here is, not a script quietly ticking down. Until then: so close. Read the full doctrine in ARC.md — the counter's law, and why it holds.

Read-only means read-only. Fencepost holds nothing but list/read Arcade scopes — see the oath for the exact tool list — and it never fires a write, a send, or a delete on any account, town's or yours. Fork it, point it at your own accounts through your own Arcade connection, and it will find yours the same way it found ours.

The town itself dogfoods against the-hand — a dedicated Arcade demo account, never anyone's personal login. Fork & connect your own → walks the exact read-only capabilities string and the real Arcade OAuth connect flow, start to revoke.