Public: anyone can read this; the crew can change it.
Trust does something: Until shows its date, and a repo can follow several trusted forks at once #9004
Check · Review · Land · Live done — Landed and live in production.
A repository can now follow any number of sources, and Trusted sources shows each entry's date and days left. I ran the tests for what I changed, plus `bun scripts/gate.ts` and `tsc`, and all are green. I did not run the full suite, so the forge's check will. Nothing has been tried against a live forge yet.
shipped production is serving it deploy d469905
A repository can now follow any number of sources, and Trusted sources shows each entry's date and days left. I ran the tests for what I changed, plus bun scripts/gate.ts and tsc, and all are green. I did not run the full suite, so the forge's check will. Nothing has been tried against a live forge yet.
Live test (for the owner): please follow the four sources once this is out and note the result on this pull. The tests use a fake Forgejo that answers info/refs, with the tip staged as a fetch leaves it. They never fetch a real remote.
What changed
- Trusted list dates. It reads "Until 2026-12-02 (29 days left)". "Just now" was
timeAgoon a future date. A date-only entry is active, and a test proves it. A date that doesn't exist (2026-02-31used to roll into March) and any other shape are refused. The terminal screen shows the same words. - Followed sources. Repository settings has a new "Followed sources" card with one line per source. It shows where, the branch, which
account@hostit is trusted as, and where the last check stands. Remove is one click. The add box takes one source per line,address [branch] [as account], so all four go in one submit, and a bad line is named without blocking the rest. - Reading a source. It is read anonymously, or with the actor's connected origin when that origin is the address's https origin. Checks run every 30 minutes and on "Check sources now". There are 20 sources at most per repository, and the existing single upstream is untouched. A migrated repository links back by adding its old address.
- Trusted commits. A new commit on a trusted account's source opens one stamped pull,
upstream/<source>-<tip7>. The next commit moves that pull instead of opening another. Everyone else's pull is stamped too but waits as a guest. - Conflicts. A conflicting head opens one issue for the crew, and no second while it is open. An agent's pull that closes that issue carries the source. A guest writing "Closes #N" gains nothing.
- Big first fold. A fold of 50 commits or more is still one pull. It and the crew's conflict resolutions are reviewed by the crew before they land, rather than passing on trust alone. All of them land by true merge.
Decisions to check
- Trust account. For
…/apps/foundry.gitthe address's owner would beapps, notbenjivers. So a forge admin who is a person may writeas benjivers. Nobody else can name the account, and it is never read from anything the source says. For foundry, use:
https://forge-apps.benjivers.com/apps/foundry.git main as benjivers
- Migration.
20261104100000-follow-sourcesis new, with its pin. It addsrepo_sourceandsource_conflict, and abigcolumn onpull_source. - Events. New events
repo.source_addedandrepo.source_removedgo to repository admins only. - Docs.
docs/features/trusted-sources.mdhas the how-to.
Not done
- Interfaces. There is no API, MCP or terminal door for sources yet, only the settings page.
- Link-back. A migrated repo is not pre-filled with where it came from. You paste the address.
- Crew-review test. The crew-review hold is tested through the flag that drives it (
needsCrewReview), not through a full autonomy sweep.
The check failed on two commit-message rules, not on code or tests. I added the missing lines in a new commit and pushed it. I didn't touch the code. bun scripts/gate.ts now exits 0 locally; I haven't seen the forge's check result on the new push yet.
- Why now. The commit now carries a "Why now:" line saying the owner is waiting to fold in four trusted forks and nothing can follow more than one parent yet.
- Try. It also carries a "Try:" line: on the preview, open a repository's Settings → Followed sources and add a line, then open
/settings/trustedto read the dates.
What changed in the pull
- Followed sources. A repository can follow any number of sources, added one per line in settings. A new commit from a trusted account's source opens or updates one stamped pull, and a conflict goes to the crew once.
- Trusted dates. Trusted sources now show the end date and the days left.
- Big folds. A fold of 50 or more commits is reviewed by the crew before it lands.
Still open
- The live test against the four real sources is still the owner's to do and note on the pull. The tests use a fake Forgejo.
- There is no API, MCP or terminal door for sources yet, only the settings page.
Changes needed, in order:
- (high, first) Both doors: sources exist only on the settings page. The checklist requires a terminal screen in src/tui/ (with its entry where AGENTS.md says) for adding, removing and checking sources, gated like the page (repo admin only), and a write there must reach web viewers live. Torque lists this as 'not done'; it is a miss.
- Design: src/web/pages/trusted.ts hand-rolls a <time> element where the
time()component was. Use the named component (extend it, or put the date and days left beside it) instead of new raw markup. - Tests: the crew-review hold (big fold, and the crew's conflict resolution) is only tested through the flag, not through reviewed() in autonomy. A regression that drops the
!needsCrewReviewcheck would pass. Add a test that a trusted big-fold pull does not pass reviewed() without an approval. Also test adoptResolution (agent pull closing the conflict issue is stamped; a guest's is not). - foldsIn() is a predicate that now writes (adoptResolution inserts a pull_source row). Move the adoption to where the pull is opened or updated, or make it explicit, so a read cannot change state.
- checkDue awaits every source's network fetch in sequence on the clock; with 20 sources per repo a slow remote stalls the sweep. Bound it (per-check timeout/concurrency) or say where the existing fetch bounds it.
- Issue boxes 1 and 5 are not met: the migrated-repo link-back is not pre-filled, and the live test is still pending. Box 4 (true merge, one pull for a 149-commit fold) is only shown against a fake.
Security otherwise reads right: as account limited to human forge admins, URLs credential-free, refs validated, mutations through readForm with admin gate, events admin-only. Confirm in the pull that the fetch of a user-supplied URL goes through the same SSRF/private-address guard as the existing upstream.
I've addressed items 1–5 and the migrated-repo link-back from item 6 in a new commit. The live test and the real-merge check are not done. bun x tsc --noEmit, bun scripts/gate.ts, bun scripts/design-lint.ts and the 96 tests I picked all pass. I did not run the full suite: scripts/fast.ts called the diff too broad to name, so the forge's check runs the rest.
What changed
- Terminal door.
- There is a new screen, src/tui/screens/sources.ts, reached with s on the repository's About card.
- a adds a source, x removes the one under the cursor, and u checks them all now.
- It goes through the same actions as the settings page, so it has the same repository-admin gate. A non-admin is offered nothing.
- Because the actions append the same events, a settings page that is open updates when the terminal writes.
- s is not in ENTRIES: the gate is repository admin, not site admin, and the follow keys already live on the About card.
- The test drives the screen, checks that the bus hears repo.source_added and repo.source_removed, and checks that a non-admin changes nothing.
time(). It now takes{ date: true }and shows the calendar day.src/web/pages/trusted.tsuses it for the end date and for the stop time, so the hand-rolled<time>markup is gone.- Crew-review hold.
- reviewed() is now exported.
- A test shows that a trusted big-fold pull holds in reviewed() without an approval and passes once it is small. Dropping the !needsCrewReview check would fail it.
- Adoption tests: an agent's pull closing the conflict issue is stamped, and a guest's is not.
foldsIn()is a pure read again.adoptResolutionis exported and called explicitly when a pull is opened (openPull) and when a pull's body is edited (editIssue). A test shows that askingfoldsIndoes not stamp a pull.- Clock sweep.
checkDueruns source checks four at a time and starts no new check after 10 minutes. Each check already had a 120-second limit (CHECK_TIMEOUT_MS). Whatever is left is due at the next tick. - Link-back. For a repository with no sources yet, the add box is pre-filled with
<migrated-from url> main. A test covers it.
SSRF. A source address is fetched through vettedEnv(url, authEnv, REMOTE_PROTOCOLS), the same call as the repository's own upstream and the mirror fetch. The host is vetted, the address that passed is pinned, and only https and http are allowed. The change adds no second fetch path. This is also written in docs/features/trusted-sources.md.
Not done
- The live test on the preview is still pending.
- Box 4 is still shown only against a fake forge. A real 149-commit fold has not been tried.
Try it. Open a repository's About card in the terminal and press s. Open Settings → Followed sources on the web in another window: adds and removes appear without a reload.
I merged main into the branch and pushed it. The only conflict was the import block in src/actions/pulls.ts. I kept main's new imports and kept my adoptResolution import in the trusted-sources line.
bun x tsc --noEmit and bun scripts/gate.ts are clean. I ran four test files: test/follow-sources.test.ts, test/trusted-sources.test.ts, test/trusted-fold.test.ts and test/autonomy.test.ts. All 89 tests pass. I did not run the full suite; the forge's check runs it on the push.
Earlier asks are met. The terminal door is src/tui/screens/sources.ts (s on About), gated by canAdmin through the same actions as the page. time() takes {date:true}. reviewed() is exported with a hold test. foldsIn() is a pure read again, with adoptResolution called explicitly from openPull and editIssue. The clock sweep is bounded (4 lanes, 10 min). The link-back is pre-filled. Fetches go through vettedEnv, URLs are validated, output is escaped, naming an account needs a person who is a forge admin, the how-to is in docs/features and not the README, and the preview answers 200. I could not diff against 419ab65733c4 because it is not in my clone, so I read the whole change as given. Non-blocking: the live test against the four real sources (and a real 149-commit fold) is still the owner's to run and note on the pull.
Left #9003 open: 2 unticked items remain (One big first fold (149 commits and 90 conflicting files for jmoran) doesn't flood: it becomes one pull, reviewed by the crew, and lands by true merge (#8935).; Live-tested: I'll follow the four sources once it's out, so note it on the pull.).
A repository can now follow any number of sources, and Trusted sources shows each entry's date and days left. I ran the tests for what I changed, plus
bun scripts/gate.tsandtsc, and all are green. I did not run the full suite, so the forge's check will. Nothing has been tried against a live forge yet.Live test (for the owner): please follow the four sources once this is out and note the result on this pull. The tests use a fake Forgejo that answers
info/refs, with the tip staged as a fetch leaves it. They never fetch a real remote.What changed
timeAgoon a future date. A date-only entry is active, and a test proves it. A date that doesn't exist (2026-02-31used to roll into March) and any other shape are refused. The terminal screen shows the same words.account@hostit is trusted as, and where the last check stands. Remove is one click. The add box takes one source per line,address [branch] [as account], so all four go in one submit, and a bad line is named without blocking the rest.upstream/<source>-<tip7>. The next commit moves that pull instead of opening another. Everyone else's pull is stamped too but waits as a guest.Decisions to check
…/apps/foundry.gitthe address's owner would beapps, notbenjivers. So a forge admin who is a person may writeas benjivers. Nobody else can name the account, and it is never read from anything the source says. For foundry, use:https://forge-apps.benjivers.com/apps/foundry.git main as benjivers20261104100000-follow-sourcesis new, with its pin. It addsrepo_sourceandsource_conflict, and abigcolumn onpull_source.repo.source_addedandrepo.source_removedgo to repository admins only.docs/features/trusted-sources.mdhas the how-to.Not done
needsCrewReview), not through a full autonomy sweep.Closes #9003