Skip to content

feat(claims): read claims and readiness from the upstream tree - #192

Merged
kixelated merged 2 commits into
mainfrom
quest/m0/helpers/claims
Oct 22, 2026
Merged

kixelated merged 2 commits into
mainfrom
quest/m0/helpers/claims

Conversation

@kixelated

@kixelated kixelated commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Completes quest/m0/helpers/claims.md (plan at d3d721c). A spawn on 2026-10-21 skipped two quests that had partly landed as "held by branch ..., with no open PR". quest unblocked --unclaimed and quest start also read readiness from the local checkout, so a stale checkout could offer a finished or deleted quest.

Changes

  • Merged heads (src/cli/claims.ts). A pushed quest branch with no open PR is checked against GitHub. If its tip is the head of a merged PR from that branch, it holds nothing. The check is one pulls?state=closed&head=<owner>:<branch> request per such branch. A closed, unmerged PR's branch still holds its quest, and so does a merged branch that moved on after merging. held() now returns { claims, landed }. quest start replaces a landed branch with --force-with-lease on that tip; every other claim push leases on the branch not existing, which matches the old non-forced push. quest mv gets the same rule through claims().
  • Upstream tree (src/cli/tree.ts, src/cli/main.ts). snapshot(root, commit) reads the quest tree from a commit with one ls-tree -r and one cat-file --batch. Paths are relative to --root, and the commit's file list backs link checks. quest unblocked --unclaimed and quest start validate and rank the fetched upstream default branch instead of the checkout. A quest that exists only locally is refused with the existing "not on the upstream default branch" message. Plain quest unblocked and quest unblocked <path> still read the checkout. Without the remote, --unclaimed falls back to the checkout with the existing warning.
  • Head repository (src/cli/github.ts). remoteRepository(root, remote, push) reads the fetch or push URL, trying the configured URL first so insteadOf rewrites still name GitHub. upstream(), pullRequest(), and the push side all use it. The head repository now comes from the push URL, so a remote that fetches from upstream and pushes to a fork claims from that fork. A push URL that is not on GitHub falls back to the fetched repository. githubRepository also accepts HTTPS with credentials, ssh:// with a port, any scp-like user, and a trailing slash.
  • startQuest(root, target, path, title, deps) takes a Target from target(): the remote, its upstream, and the fetched base and its tree. The CLI reads the tree it checks from the same commit the claim builds on. remoteHead/ensure moved to claims.ts as upstreamHead/ensure.
  • README and --help describe the upstream tree, landed branches, and push-URL forks. This PR deletes the quest and its entry in quest/m0/helpers/README.md.

The plan asked to reuse a tree loader from kixelated/quest#169. That guard only runs git cat-file -e on one file, so snapshot() is new, and it lives beside the disk loader.

Validation

  • just check: passed.
  • just test: passed.
  • New tests in test/start.test.ts:
    • A merged-head branch is not a claim, and start replaces it, upstream and in a fork.
    • A closed, unmerged PR's branch still holds its quest, and so does a merged branch whose tip moved on.
    • In a checkout behind upstream, unblocked --unclaimed ranks upstream's ready quest. start refuses the quest upstream finished and claims the one that is locally blocked but ready upstream.
    • A remote with an HTTPS fetch URL and an SSH push URL to a fork pushes to the fork, opens the PR upstream, and sees the fork's branch as a claim.
    • URL parsing variants.
  • Existing tests now land their tree changes upstream, since local edits no longer affect readiness for --unclaimed/start.

Suggested follow-ups

  • Report landed quest branches, which hold nothing but stay on repositories without auto-delete. A quest unblocked --unclaimed note, or a cleanup command, could list them for deletion.
  • kix.quest (cloudflare/src/github/state.ts) counts every quest/* ref as a claim. Apply the same merged-head rule there so its board agrees with the CLI.
  • A remote that fetches from GitHub but pushes to a different forge falls back to the fetched repository as head, as it did before this PR. quest start then fails loudly when GitHub refuses the PR. Treating that push target as a separate branch-only source would need its own design (review thread).
  • The Windows arm64 Release lifecycle check sometimes fails with EBUSY when it removes its temp directory after passing. That happened here and on quest/m0/worktree (run 39679528766). Find which process holds the directory, rather than retrying the removal.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits October 21, 2026 22:44
Quest-Claim: 265ab2d5c3627d77
A quest branch whose tip is a merged PR's head no longer counts as a claim, and quest start replaces it with a lease on that tip; a closed, unmerged PR's branch still holds its quest. quest unblocked --unclaimed and quest start rank and validate the fetched upstream default branch's tree instead of the checkout. The head repository comes from the remote's push URL, parsed through remoteRepository in github.ts.

Completes quest/m0/helpers/claims.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Read claims from the upstream tree feat(claims): read claims and readiness from the upstream tree Oct 22, 2026
@kixelated
kixelated marked this pull request as ready for review October 22, 2026 06:26
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T06:30:16.619200Z 1f197be Draft marked ready
🔒 Security Review ✅ Completed 2026-10-22T06:38:36.544749Z 1f197be Draft marked ready
ℹ️ About Codex in GitHub

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

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

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f197bedae

ℹ️ About Codex in GitHub

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

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

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

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

Comment thread src/cli/claims.ts
Comment on lines +89 to +90
const pushed = remoteRepository(root, remote, true).repository;
const head = pushed === null || same(pushed, self) ? self : (await repositoryInfo(client, pushed)).repository;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat a non-GitHub push target as PR-less

When a remote fetches from GitHub but has an explicit push URL on GitLab, a local server, or another non-GitHub forge, this fallback incorrectly identifies the fetched GitHub repository as the head repository. Consequently held() never checks branches at the actual push target, and quest start pushes there before trying to open a GitHub PR whose head branch does not exist on GitHub; the PR request fails and cleanup deletes the just-pushed branch. Preserve the GitHub repository for upstream-tree reads, but represent the non-GitHub push target separately so it is checked as a branch-only source and no PR is attempted.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Leaving this as is for now. Before this PR, the head was always the fetched repository whatever the push URL said, so the fallback keeps the old behavior for that setup instead of adding a third mode. It also fails loudly: GitHub refuses to open the PR, the just-pushed claim branch is deleted with its lease, and quest start exits 1. A GitHub fetch URL with a non-GitHub push URL (a mirror, say) is rare, and making it a branch-only claim source would need its own design, for example whether unblocked --unclaimed should check branches on two forges. I listed it as a suggested follow-up in the report.

(Written by Claude Opus 5.5)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Outcome: the quest is complete with no open decisions, so this PR is ready for review. just check and just test pass locally, and all 17 CI checks pass. The Windows arm64 Release job passed on re-run; its first failure was the known EBUSY cleanup flake. Codex left one finding, about a GitHub fetch URL with a non-GitHub push URL. I disagreed in the thread, since the fallback keeps the behavior from before this PR, and listed it as a follow-up.

(Written by Claude Opus 5.5)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary: enabling auto-merge on head 1f197bedae5536945baae325f0061da3fbf1c02e.

  • All 17 required checks pass on this head, and the branch merges cleanly into main.
  • Codex reviewed this head. Its one finding, about a GitHub fetch URL paired with a non-GitHub push URL, was answered in the review thread: the fallback keeps the behavior from before this PR and fails loudly, so it is listed as a follow-up rather than fixed here.
  • quest check --base origin/main --branch quest/m0/helpers/claims, run from the base build against the head checkout, passes (47 documents ok). The PR deletes quest/m0/helpers/claims.md and its link.
  • kixelated/quest#191 also edits quest/m0/helpers/README.md. Whichever lands second needs that list conflict resolved.

The follow-ups in the PR body go to /quest-plan after merge.

(Written by Claude Opus 5.5)

@kixelated
kixelated merged commit a689e26 into main Oct 22, 2026
25 of 26 checks passed
@kixelated
kixelated deleted the quest/m0/helpers/claims branch October 22, 2026 15:38
kixelated added a commit that referenced this pull request Oct 22, 2026
Add [XS] merged claims to the Kix epic, so the board ignores branches
whose pull request merged, as the CLI does since #192. Add [S] lifecycle
EBUSY to m0, to root-cause the Windows lifecycle check failing while
removing its temp directory. Drop a merged-branch sweep and the
push-to-another-forge case.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant