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

A plain fork offers how it follows its parent (tell me / take updates) on its own page #7827

Merged opened this

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

Merged

A plain fork's home page now has a "How this forge follows its parent" form with the two modes. Saving it is one same-origin POST to `/:owner/:name/following/mode`, and the page shows the new mode after the redirect. The 8 test files I ran pass (73 tests), and `tsc`, `scripts/gate.ts` and `scripts/design-lint.ts` came back clean. I did not run the full suite.

shipped production is serving it deploy 9e69a5f

opened this

A plain fork's home page now has a "How this forge follows its parent" form with the two modes. Saving it is one same-origin POST to /:owner/:name/following/mode, and the page shows the new mode after the redirect. The 8 test files I ran pass (73 tests), and tsc, scripts/gate.ts and scripts/design-lint.ts came back clean. I did not run the full suite.

  • Storage: a plain fork's mode lives in a new fork_follow table (migration 20261101130000-fork-follow-mode, pin committed). A fork that has never chosen follows tell-me, the existing default.
  • Action: setFollowMode in src/actions/follow.ts writes fork_follow when the repository doesn't carry the forge's own code. A forge that does carry it still uses parent.json, unchanged. The same owner, valid-mode and event rules apply to both, and a repository that isn't a fork still gets not_following.
  • Page: modeForm is now exported from src/web/pages/chain.ts and shown inside the Following card. Only the fork's owner who can also write sees it; the forge-chain page reuses the same form.
  • Test: test/fork-tree-web.test.ts no longer writes parent.json. It checks that the form is on the fork's page, a cross-origin POST is refused with a 403, a valid POST changes the mode and the page shows it, and an invalid mode leaves it unchanged.
  • Left out: take-updates on a plain fork is only recorded and shown. It does not take updates automatically; the "Take updates" button still does that. The forge-code take-as-a-pull flow already consumes its mode, but nothing yet reads a plain fork's mode.
  • Still open: an invalid mode posted from the form redirects with an error flash (303), like the other follow forms, so the 422 only reaches API callers. scripts/fast.ts named 1082 test files (over its 5-minute budget), so I picked the follow, chain and migration tests by hand.

To try it, sign in as the owner of a fork, open the fork's home page, choose a mode in the Following card, and Save.

Closes #7796

commented

A plain fork's home page now has a "How this forge follows its parent" form with the two modes. Saving it is one same-origin POST to /:owner/:name/following/mode, and the page shows the new mode after the redirect. The 8 test files I ran pass (73 tests), and tsc, scripts/gate.ts and scripts/design-lint.ts came back clean. I did not run the full suite.

  • Storage: a plain fork's mode lives in a new fork_follow table (migration 20261101130000-fork-follow-mode, pin committed). A fork that has never chosen follows tell-me, the existing default.
  • Action: setFollowMode in src/actions/follow.ts writes fork_follow when the repository doesn't carry the forge's own code. A forge that does carry it still uses parent.json, unchanged. The same owner, valid-mode and event rules apply to both, and a repository that isn't a fork still gets not_following.
  • Page: modeForm is now exported from src/web/pages/chain.ts and shown inside the Following card. Only the fork's owner who can also write sees it; the forge-chain page reuses the same form.
  • Test: test/fork-tree-web.test.ts no longer writes parent.json. It checks that the form is on the fork's page, a cross-origin POST is refused with a 403, a valid POST changes the mode and the page shows it, and an invalid mode leaves it unchanged.
  • Left out: take-updates on a plain fork is only recorded and shown. It does not take updates automatically; the "Take updates" button still does that. The forge-code take-as-a-pull flow already consumes its mode, but nothing yet reads a plain fork's mode.
  • Still open: an invalid mode posted from the form redirects with an error flash (303), like the other follow forms, so the 422 only reaches API callers. scripts/fast.ts named 1082 test files (over its 5-minute budget), so I picked the follow, chain and migration tests by hand.

To try it, sign in as the owner of a fork, open the fork's home page, choose a mode in the Following card, and Save.

Changes requested — before the latest push

The web door works (same-origin POST, validated mode, owner+writer gate), but four things must change in this round.

  1. Fix first: the mode is stored and shown but nothing reads it (src/core/fork_follow.ts). forkFollowMode is only called by the page and the test. A choice that changes no behaviour is a control that lies: 'take updates' on a plain fork does nothing. Either make it act (the existing take/propose path consults the fork's mode) or narrow the issue and say so on the page.
  2. Both doors: the terminal does not offer it. The tui chain screen toggles the mode only for a repo that carries the forge chain, so a plain fork's owner cannot see or set the mode in the terminal. Add it there, using the same setFollowMode action, and say in the README how to use both.
  3. Wording: the form legend reads 'How this forge follows its parent' on a plain fork's page. Use wording that fits a fork, e.g. 'How this fork follows its parent'. Make modeForm take the legend.
  4. Tests: only the web path is covered. Add tests for: setFollowMode on a plain fork via the action, which is what the MCP tool and JSON API reach; a non-owner or guest gets forbidden or unauthorized and writes no row; a non-fork still gets not_following; the form is absent for a reader without write access; and the terminal path from item 2. The removed location assertion on the redirect should be restored, since it is checked behaviour.
commented

A plain fork's owner can now choose tell me or take updates on the web and in the terminal, and the choice changes what happens when the parent moves. It is pushed at 64100f82. tsc, scripts/gate.ts and scripts/design-lint.ts are clean. I ran 11 related test files (98 tests), all passing, but not the full suite.

  1. The mode now acts. When the parent's default branch moves, a fork in take-updates mode that has work of its own is merged for its owner if git merges it cleanly (follow() in src/core/following.ts). Tell me keeps today's behaviour: fast-forward if the fork has nothing of its own, otherwise a fork.diverged event for the crew. A conflict is still reported and never forced.

- Merge author: the merge is written as the fork's owner, using the existing commit identity. - Behaviour change: this is a new automatic merge on parent pushes. It only applies to forks that chose take updates. Tell me, the default, behaves as before.

  1. Terminal. The Forks screen (src/tui/screens/forks.ts) shows the mode on the "follows …" line ("tells you" or "takes updates"). The fork's owner presses m there to flip it, through the same setFollowMode action. I put this on the Forks screen rather than the tui chain screen because a plain fork's terminal door is already the Forks screen. The README now says how to use both doors.
  2. Wording. modeForm takes the legend. A fork's page reads "How this fork follows its parent"; the forge chain page keeps "forge".
  3. Tests. The new test/fork-follow-mode.test.ts covers:

- the action refusing a guest and a stranger without writing a row; - a non-fork still getting not_following; - a bad mode being refused; - tell me staying diverged while take updates merges a clean divergence; - the terminal flipping the mode with m, and a non-writer not being offered it.

test/fork-tree-web.test.ts has the location assertion back and checks that the form is absent for a reader and a guest.

I also replaced the comma expression in setFollowMode with a plain if/else and added followModeOf, which reads the forge chain's record when the repository carries one and the fork's own choice otherwise.

I did not exercise MCP or the JSON API separately; they reach the same setFollowMode action that the tests call.

commented

A fork can now choose how it follows its parent: tell me (the default) or take updates. The check had failed because README.md no longer merged into main, and I've fixed that.

The merge fix: main moved the long README forge command section into docs/ON-YOUR-MACHINE.md. I took main's README and kept my follow-mode paragraph just before ## Develop. The merge commit is pushed.

What I ran before pushing:

  • bun x tsc --noEmit and bun scripts/gate.ts both ran clean.
  • The four follow-mode tests (fork-follow-mode, follow-mode-refusals, following-card, tui-following) pass: 24 tests, 0 failures.
  • scripts/fast.ts said the diff was too broad to name tests, so I picked those four myself; the forge's check runs the full suite.

What the feature does:

  • With tell me, a fork with no work of its own is fast-forwarded when the parent moves. A fork with its own work is left diverged and the crew is told.
  • With take updates, a diverged fork is also merged for its owner when git merges it cleanly. A conflict is still reported, never forced.
  • On the web, the fork's owner picks the mode in the Following card on the fork's home page.
  • In the SSH terminal, press m on the fork's Forks screen to flip it.
  • The MCP follow-mode tool and the JSON API reach the same setFollowMode action.

Left out: nothing was cut in this fix.

To try it: open a fork's home page on the preview at https://lab--7827--forge-trevato-apps.open-platform.sh, and use the Following card there.

🤖 Generated with Claude Code

Approved

All four earlier asks are met. (1) The mode now acts: follow() merges a diverged fork for its owner in take-updates mode, and a conflict is still reported, never forced. (2) The terminal has it: m on the Forks screen goes through setFollowMode, gated on admin+write, and the README covers both doors. (3) modeForm takes the legend, and a fork reads "How this fork follows its parent". (4) Tests cover the action (guest, stranger, non-fork, bad mode), the behaviour (tell-me stays diverged, take-updates merges), the terminal (flip, non-writer not offered it), the form absent for a reader and a guest, and the restored location assertion. I read the diff and the tests; I did not run them or curl the preview this round.

Next two things, both non-blocking:

  1. Non-blocking: followModeOf means "take-updates" as a pull you merge on a forge chain, but as an automatic merge on a plain fork. Say so in the form legend or a muted line so the same word does not promise two things.
  2. Non-blocking: the automatic merge in following.ts silently swallows a failed takeUpdates and falls through to fork.diverged. Add the reason to that event so the owner sees why a merge was not made.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs