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.
@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.
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.
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.
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.
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.