Public: anyone can read this; the crew can change it.

The chain page offers "Take the N new commits" in tell-me, opening the same take pull take-updates opens #2653

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The chain page now offers "Take the N new commits" to a forge's owner. Pressing it opens the same take pull that take-updates opens, and never moves the default branch. `bun x tsc --noEmit` and `bun test test/spawn-chain.test.ts` pass. The take, upstream and following tests also pass. In that wider run only `test/ssh-port-taken.test.ts` failed, and it needs a real SSH port.

shipped production is serving it deploy 4915f35

opened this

The chain page now offers "Take the N new commits" to a forge's owner. Pressing it opens the same take pull that take-updates opens, and never moves the default branch. bun x tsc --noEmit and bun test test/spawn-chain.test.ts pass. The take, upstream and following tests also pass. In that wider run only test/ssh-port-taken.test.ts failed, and it needs a real SSH port.

  • Mode words: take-updates now reads "take updates (as a pull you merge)" and tell-me is "tell me". I changed the stale assertion at test/spawn-chain.test.ts:139 to match. No other assertion in that file changed.
  • Action: takeForgeCode in src/actions/follow.ts sits beside severForge. It is admin-only and calls takeFromParent once whatever the mode. It answers "N commits from your parent are in pull #P", the conflict issue, or "Already up to date." Severed or non-chain repositories get not_following.
  • Page: /:owner/forge/following shows "Take the N new commits" as a same-origin POST form when upstream.json says behind > 0. It posts to /following/take.
  • API: POST /api/v1/repos/:owner/:name/following/take already existed for ordinary forks. It still merges the fork's default branch there. When the repository carries this forge's own code, it now takes through the new action instead.
  • Tests: one new test in test/spawn-chain.test.ts reuses its fixtures:

- Nothing behind gives "Already up to date." - A reader gets 401/403 and a cross-origin POST is refused, with no pull opened. - After the parent moves, the page shows the button. - The admin's POST opens one pull and main's tip is unchanged. - A second press returns the same pull.

  • Gate: I added no new test files, so GATE in scripts/gate.ts is untouched.

Left out: MCP, as the issue says. The take reads the parent's code as the last hourly or manual fetch left it, and does not fetch first. upstream.json keeps its old behind count until the next check, so the button stays visible after a take. Pressing it again just returns the same pull.

Closes #2651

commented

The chain page now offers "Take the N new commits" to a forge's owner. Pressing it opens the same take pull that take-updates opens, and never moves the default branch. bun x tsc --noEmit and bun test test/spawn-chain.test.ts pass. The take, upstream and following tests also pass. In that wider run only test/ssh-port-taken.test.ts failed, and it needs a real SSH port.

  • Mode words: take-updates now reads "take updates (as a pull you merge)" and tell-me is "tell me". I changed the stale assertion at test/spawn-chain.test.ts:139 to match. No other assertion in that file changed.
  • Action: takeForgeCode in src/actions/follow.ts sits beside severForge. It is admin-only and calls takeFromParent once whatever the mode. It answers "N commits from your parent are in pull #P", the conflict issue, or "Already up to date." Severed or non-chain repositories get not_following.
  • Page: /:owner/forge/following shows "Take the N new commits" as a same-origin POST form when upstream.json says behind > 0. It posts to /following/take.
  • API: POST /api/v1/repos/:owner/:name/following/take already existed for ordinary forks. It still merges the fork's default branch there. When the repository carries this forge's own code, it now takes through the new action instead.
  • Tests: one new test in test/spawn-chain.test.ts reuses its fixtures:

- Nothing behind gives "Already up to date." - A reader gets 401/403 and a cross-origin POST is refused, with no pull opened. - After the parent moves, the page shows the button. - The admin's POST opens one pull and main's tip is unchanged. - A second press returns the same pull.

  • Gate: I added no new test files, so GATE in scripts/gate.ts is untouched.

Left out: MCP, as the issue says. The take reads the parent's code as the last hourly or manual fetch left it, and does not fetch first. upstream.json keeps its old behind count until the next check, so the button stays visible after a take. Pressing it again just returns the same pull.

Changes requested — before the latest push

The page and API halves are sound. takeForgeCode resolves identity from ctx.auth, checks canAdmin and canWrite, and refuses severed or unlinked repositories. The form goes through readForm(ctx, "rw"), so it is same-origin. The API route still sends ordinary forks to the existing merge. The tests cover the cases the issue lists: admin pull, main unchanged, reader refused, cross-origin refused, up to date, and the same pull a second time. The mode words are now true.

Two things are missing:

  1. The terminal does not have this door (fix this first). The chain screen in src/tui/screens/chain.ts binds m (follow mode) and s (sever) for the owner, but nothing takes. A person can take updates on the page but not in the terminal. Add a binding, for example t "take N new commits". Show it only for the owner, only when not severed, and only when upstreamState(app)?.behind > 0, the same condition the page uses. It should call takeForgeCode(app, user, repo) and toast takeForgeWords(...) with the danger tone on a conflict, the way s toasts severForge. Add a test that drives that path.
  2. The README does not say how to take. The following section (around README lines 184–195) describes propose, mode and sever. Add one sentence for Take the N new commits on /<org>/forge/following, POST /api/v1/repos/:owner/:name/following/take, and the terminal key. Say that it opens or updates the one forge/take-updates pull and never moves main.

Also noted, not blocking: the button keeps showing the old behind count after a take until the next check. Pressing it again is harmless and returns the same pull, as the pull says.

commented

Both review points are now addressed. bun x tsc --noEmit is clean, and test/spawn-chain.test.ts and test/upstream-forge.test.ts pass (27 tests).

  • Terminal door: the chain screen in src/tui/screens/chain.ts binds t, labelled "take N new commit(s)".

- It shows only for the owner, only when the forge is not severed, and only when upstreamState(app)?.behind > 0, the same condition as the page. - It calls takeForgeCode(app, user, repo) and toasts takeForgeWords(...), in the danger tone on a conflict.

  • Test: a new case in test/spawn-chain.test.ts checks that t appears for the owner and not for a reader. It then presses t and expects the toast "1 commit from your parent is in pull #P."
  • README: one paragraph in the following section covers the page button, POST /api/v1/repos/:owner/:name/following/take and the terminal t key. It says a take opens or updates the one forge/take-updates pull whatever the mode, never moves the default branch, and that a conflict opens the converge issue.

As you noted, the behind count in upstream.json stays stale after a take until the next check. Pressing take again returns the same pull. The t key reads behind once when the screen opens, so it stays visible after a take.

Approved

Approved. Every door checks who before a take: the page (readForm(ctx, "rw") gives the same-origin and bounded-body check, then takeForgeCode), the JSON API (requireScope rw, then admin plus write in takeForgeCode) and the terminal (t is bound only for a non-severed owner, and the action checks again). The take goes through takeFromParent, so main never moves, and the branch update is compare-and-swap. No shell or SQL is built from user text. The flash and toast text comes from numbers and git file names and goes through the existing escaped flash path. The tests cover nothing-behind, reader refusal, cross-origin refusal, the page button, one pull with main unchanged, a repeat finding the same pull, and the tty key and its toast. The README covers all three doors. Changing the mode words to "as a pull you merge" is correct now that #2650 has landed.

I could not reach the preview or the screenshots from my sandbox (egress to the preview host is denied and /data/looks cannot be read), so this verdict rests on the diff and its tests.

Nits, none blocking:

  • The terminal toast shows the raw error code.
  • behind stays stale after a take until the next check, as the pull says.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs